Skip to content

OliveTin

Browser-based interface for running predefined shell commands on Kubernetes. OliveTin lets you expose safe, well-defined system actions — restart a service, trigger a backup, run a diagnostic — as clickable buttons in a clean web UI, without giving users direct shell access.

Do not expose OliveTin to the public internet without authentication

OliveTin executes shell commands on the server. Without authentication, anyone who can reach the URL can run all configured actions. Deploy behind an auth proxy (Authelia, Authentik, Traefik ForwardAuth) or restrict access to a trusted network or VPN.

Key Features

  • ConfigMap-based actions — define shell commands in YAML, mounted as a ConfigMap
  • No external dependencies — no database, no state, stateless by design
  • Prometheus metrics — optional scraping with ServiceMonitor support
  • Gateway API and Ingress — expose the UI with either classic Ingress or HTTPRoute
  • External Secrets Operator — render ExternalSecret resources for credentials used by custom actions
  • Dual-stack Services — optional ipFamilyPolicy and ipFamilies controls
  • Confirmation prompts — require user confirmation before running destructive commands
  • Icon and title customization — human-friendly labels for each action
  • Lightweight — minimal resource footprint

Security Scan

Framework Score
MITRE + NSA + SOC2 95%

Security posture: acceptable.

Installation

HTTPS repository:

helm repo add helmforge https://repo.helmforge.dev
helm repo update
helm install olivetin helmforge/olivetin

OCI registry:

helm install olivetin oci://ghcr.io/helmforgedev/helm/olivetin

Deployment Examples

# values.yaml — Minimal setup with a few example actions
config: |
  actions:
    - title: "Ping Google"
      shell: "ping -c 1 google.com"
      icon: "ping"

    - title: "Show Disk Usage"
      shell: "df -h"
      icon: "disk"

    - title: "Show Memory"
      shell: "free -h"
      icon: "memory"

ingress:
  enabled: true
  ingressClassName: traefik
  hosts:
    - host: olivetin.internal.example.com
      paths:
        - path: /
          pathType: Prefix
# values.yaml — Advanced action definitions with confirmation, timeouts, and arguments
config: |
  actions:
    - title: "Restart nginx"
      shell: "kubectl rollout restart deployment/nginx -n web"
      icon: "restart"
      confirmBeforeStart: true
      timeout: 30

    - title: "Trigger Backup"
      shell: "kubectl create job backup-manual --from=cronjob/database-backup -n database"
      icon: "backup"
      confirmBeforeStart: true
      timeout: 60

    - title: "Get Pod Logs"
      shell: "kubectl logs -n {{ namespace }} {{ pod }} --tail=100"
      icon: "logs"
      arguments:
        - name: namespace
          title: "Namespace"
          default: default
        - name: pod
          title: "Pod name"

    - title: "Scale Deployment"
      shell: "kubectl scale deployment {{ deployment }} --replicas={{ replicas }} -n {{ namespace }}"
      icon: "scale"
      confirmBeforeStart: true
      arguments:
        - name: namespace
          title: "Namespace"
          default: default
        - name: deployment
          title: "Deployment"
        - name: replicas
          title: "Replica count"
          default: "1"

ingress:
  enabled: true
  ingressClassName: traefik
  hosts:
    - host: olivetin.internal.example.com
      paths:
        - path: /
          pathType: Prefix
# values.yaml — OliveTin with Prometheus metrics and ServiceMonitor
config: |
  actions:
    - title: "Ping Google"
      shell: "ping -c 1 google.com"

metrics:
  enabled: true
  serviceMonitor:
    enabled: true
    interval: 30s
    scrapeTimeout: 10s

ingress:
  enabled: true
  ingressClassName: traefik
  hosts:
    - host: olivetin.internal.example.com
      paths:
        - path: /
          pathType: Prefix
# values.yaml — OliveTin behind Traefik ForwardAuth (Authelia example)
config: |
  actions:
    - title: "Ping Google"
      shell: "ping -c 1 google.com"

ingress:
  enabled: true
  ingressClassName: traefik
  annotations:
    traefik.ingress.kubernetes.io/router.middlewares: auth-authelia-forwardauth@kubernetescrd
  hosts:
    - host: olivetin.example.com
      paths:
        - path: /
          pathType: Prefix
  tls:
    - secretName: olivetin-tls
      hosts:
        - olivetin.example.com
# values.yaml — expose OliveTin through Gateway API
config: |
  actions:
    - title: "Show Disk Usage"
      shell: "df -h"

gatewayAPI:
  enabled: true
  httpRoutes:
    - name: olivetin
      spec:
        parentRefs:
          - name: internal-gateway
            namespace: gateway-system
        hostnames:
          - olivetin.internal.example.com
        rules:
          - matches:
              - path:
                  type: PathPrefix
                  value: /
# values.yaml — credentials for custom actions managed by External Secrets Operator
config: |
  actions:
    - title: "Trigger API"
      shell: "curl -H \"Authorization: Bearer ${API_TOKEN}\" https://api.example.com/jobs"

extraEnv:
  - name: API_TOKEN
    valueFrom:
      secretKeyRef:
        name: olivetin-command-credentials
        key: API_TOKEN

externalSecrets:
  enabled: true
  apiVersion: external-secrets.io/v1
  refreshInterval: 1h
  items:
    - name: command-credentials
      spec:
        secretStoreRef:
          name: platform-secrets
          kind: ClusterSecretStore
        target:
          name: olivetin-command-credentials
          creationPolicy: Owner
        data:
          - secretKey: API_TOKEN
            remoteRef:
              key: olivetin/api-token

Configuration Reference

Core

Parameter Type Default Description
nameOverride string "" Override the chart name.
fullnameOverride string "" Override the full release name.
commonLabels object {} Extra labels added to all resources.

Image

Parameter Type Default Description
image.repository string docker.io/jamesread/olivetin OliveTin container image.
image.tag string "3000.14.0" Image tag.
image.pullPolicy string IfNotPresent Image pull policy.
imagePullSecrets array [] Pull secrets for private registries.

Config Bootstrap

Parameter Type Default Description
configInit.enabled boolean true Prepare writable OliveTin runtime files.
configInit.resources object requests/limits set Resource guardrails for the init container.
configInit.image.tag string "1.37" BusyBox tag used by the config bootstrap helper.

OliveTin Configuration

Parameter Type Default Description
olivetin.port integer 1337 Internal HTTP port for the OliveTin container.
olivetin.extraEnv array [] Extra environment variables injected into the container.
config string (default ping action) OliveTin YAML configuration mounted at /config/config.yaml.
config is mounted as a ConfigMap

The entire config block is stored in a Kubernetes ConfigMap and mounted at /config/config.yaml. Any change to config during a Helm upgrade will trigger a pod restart to pick up the new configuration. Keep action definitions in version control alongside your values files.

The config block supports the full OliveTin configuration schema. Key action options:

Action Field Description
title Display name shown on the button in the web UI.
shell Shell command to execute.
icon Button icon name (uses OliveTin’s built-in icon set).
confirmBeforeStart Show a confirmation dialog before executing (default: false).
timeout Execution timeout in seconds (default: 3).
arguments List of user-provided arguments interpolated into shell via {{ }}.

See the full OliveTin configuration reference for all available options.

Metrics

Parameter Type Default Description
metrics.enabled boolean false Enable Prometheus metrics scraping annotations.
metrics.serviceMonitor.enabled boolean false Create a ServiceMonitor for Prometheus Operator.
metrics.serviceMonitor.namespace string "" Namespace for the ServiceMonitor (defaults to chart).
metrics.serviceMonitor.labels object {} Extra labels applied to the ServiceMonitor.
metrics.serviceMonitor.interval string 30s Prometheus scrape interval.
metrics.serviceMonitor.scrapeTimeout string 10s Prometheus scrape timeout.

Persistence

OliveTin is stateless — the config lives in a ConfigMap, and action logs are ephemeral. Persistence is optional and only needed if your actions produce output files that must survive pod restarts.

Parameter Type Default Description
persistence.enabled boolean false Enable a PVC for custom data or output files.
persistence.size string 1Gi PVC size.
persistence.storageClass string "" StorageClass for the PVC.
persistence.accessModes array ["ReadWriteOnce"] PVC access modes.
persistence.existingClaim string "" Use an existing PVC instead of creating one.

Service

Parameter Type Default Description
service.type string ClusterIP Kubernetes service type.
service.port integer 80 Service port exposed to the cluster.
service.annotations object {} Annotations for the Service.
service.ipFamilyPolicy string omitted Service IP family policy: SingleStack, PreferDualStack, or RequireDualStack.
service.ipFamilies array omitted Ordered Service IP families such as IPv4 and IPv6.

Ingress

Parameter Type Default Description
ingress.enabled boolean false Enable an Ingress resource.
ingress.ingressClassName string traefik Ingress class name.
ingress.annotations object {} Annotations for the Ingress (e.g. ForwardAuth, TLS).
ingress.hosts array [] Ingress host and path rules.
ingress.tls array [] TLS configuration (secret name and hosts).

Gateway API

Use gatewayAPI when your cluster exposes applications through Gateway API instead of Ingress. The chart renders HTTPRoute resources and routes them to the OliveTin Service by default.

Parameter Type Default Description
gatewayAPI.enabled boolean false Render Gateway API HTTPRoute resources.
gatewayAPI.httpRoutes array [] HTTPRoute definitions to render.

External Secrets Operator

External Secrets can materialize credentials for custom actions without committing secrets to the values file.

Parameter Type Default Description
externalSecrets.enabled boolean false Render ExternalSecret resources.
externalSecrets.apiVersion string external-secrets.io/v1 ExternalSecret API version.
externalSecrets.refreshInterval string 1h Default refresh interval for items that do not set one.
externalSecrets.items array [] ExternalSecret definitions. Each item requires a full spec.

Probes

Parameter Type Default Description
probes.startup.enabled boolean true Enable startup probe.
probes.startup.initialDelaySeconds integer 5 Startup probe initial delay.
probes.startup.periodSeconds integer 5 Startup probe period.
probes.startup.timeoutSeconds integer 3 Startup probe timeout.
probes.startup.failureThreshold integer 30 Startup probe failure threshold.
probes.liveness.enabled boolean true Enable liveness probe.
probes.liveness.initialDelaySeconds integer 0 Liveness probe initial delay.
probes.liveness.periodSeconds integer 15 Liveness probe period.
probes.liveness.timeoutSeconds integer 5 Liveness probe timeout.
probes.liveness.failureThreshold integer 3 Liveness probe failure threshold.
probes.readiness.enabled boolean true Enable readiness probe.
probes.readiness.initialDelaySeconds integer 0 Readiness probe initial delay.
probes.readiness.periodSeconds integer 10 Readiness probe period.
probes.readiness.timeoutSeconds integer 5 Readiness probe timeout.
probes.readiness.failureThreshold integer 3 Readiness probe failure threshold.

Resources and Security

Parameter Type Default Description
resources object requests/limits set CPU and memory requests and limits.
podSecurityContext object hardened defaults Pod-level security context.
securityContext object hardened defaults Container-level security context.

Service Account

Parameter Type Default Description
serviceAccount.create boolean false Create a dedicated ServiceAccount.
serviceAccount.name string "" Override the ServiceAccount name.
serviceAccount.annotations object {} Annotations for the ServiceAccount.
serviceAccount.automountServiceAccountToken boolean false Mount the API token into pods.

Scheduling

Parameter Type Default Description
nodeSelector object {} Node selector for scheduling.
tolerations array [] Tolerations for scheduling.
affinity object {} Affinity rules.
topologySpreadConstraints array [] Topology spread constraints.
priorityClassName string "" PriorityClass for the pod.
terminationGracePeriodSeconds integer 30 Termination grace period.
podLabels object {} Extra labels for the pod.
podAnnotations object {} Extra annotations for the pod.

Extra

Parameter Type Default Description
extraVolumes array [] Extra volumes to attach to the pod.
extraVolumeMounts array [] Extra volume mounts for the container.
extraManifests array [] Extra Kubernetes manifests deployed alongside the chart.

Common Issues

Actions timing out unexpectedly

The default action timeout in OliveTin is 3 seconds. Long-running commands (kubectl rollouts, database backups) will appear to succeed in the UI but be killed silently. Set timeout explicitly in each action that needs more time.

Run kubectl commands from OliveTin

To run kubectl commands, the OliveTin pod needs cluster access. Create a ServiceAccount with appropriate RBAC permissions and set serviceAccount.create: true with serviceAccount.annotations pointing to the account. Mount the kubeconfig or rely on in-cluster config.

More Information