Bahriya Tersane

Documentation / valkey

Network and exposure

How the chart’s NetworkPolicy interacts with a namespace’s existing policies, and how to open ValKey up to other namespaces or external clients.

The policies you’re layering on

The chart’s NetworkPolicy is a Calico projectcalico.org/v3 resource, so it requires Calico, which is the network fabric the Bahriya Kubernetes Engine installs. It adds Allow rules; it never subtracts. Where a namespace already has a baseline policy, the result is the union of the two: if either matches, traffic flows, and there is nothing to disable on the baseline side.

The chart does not restrict egress, so a calling app in app-prod can dial vk-valkey.valkey-prod.svc.cluster.local:6379 without any configuration on the calling side, unless its own namespace restricts egress.

Three reachability scenarios

1. Same-namespace clients

Default state, no values needed. Both the baseline NP and the chart NP (networkPolicy.openByDefault: true) allow ingress from any Pod in ValKey’s namespace.

2. Cross-namespace clients

Add the calling namespace(s) to networkPolicy.allowFromNamespaces. Each entry is a matchLabels block used as a namespaceSelector:

networkPolicy:
  allowFromNamespaces:
    - kubernetes.io/metadata.name: app-prod
    - kubernetes.io/metadata.name: app-staging

The auto-managed kubernetes.io/metadata.name label is available on every namespace in K8s ≥ 1.21 — no platform-side labelling is required. To allowlist by some other label scheme:

networkPolicy:
  allowFromNamespaces:
    - team: orders
    - environment: production

matchLabels is AND-combined within an entry, so combine if needed:

networkPolicy:
  allowFromNamespaces:
    - team: orders
      environment: production       # this entry matches namespaces with BOTH labels

That’s it on the receiving side. The calling app dials <release>.<valkey-namespace>.svc.cluster.local:6379 and the connection succeeds because:

  • Nothing in the chart restricts egress from app-prod.
  • Even where a baseline policy in valkey-prod blocks cross-namespace ingress by default, the chart’s NP adds an allow rule for app-prod, and Calico NetworkPolicies are additive, so the traffic is allowed.

3. External clients via Kong

Enable when external systems (CI runners, ops tooling, partners, mobile/edge clients) need to reach ValKey from outside the cluster. The chart renders a Kong TCPIngress resource that routes SNI-based traffic to ValKey’s primary Service, with IP allowlisting via the Kong ip-restriction plugin.

tls:
  enabled: true                  # REQUIRED — Kong does SSL passthrough; ValKey terminates

exposure:
  external:
    enabled: true
    host: "valkey.example.com"
    ingressClassName: "kong"
    ipAllowlist:                 # REQUIRED — empty list is refused at render time
      - "203.0.113.0/24"
      - "198.51.100.42/32"

Three guards fire at template time if you forget any of these:

Missing value Error
exposure.external.host “host is required when exposure.external.enabled”
exposure.external.ipAllowlist empty “must be a non-empty list — ValKey on the public internet without an IP allowlist is unsafe”
tls.enabled: false “tls.enabled must be true — Kong uses SSL passthrough so ValKey itself must terminate TLS”

The chart renders:

  • A configuration.konghq.com/v1beta1 TCPIngress matching the SNI hostname to the primary Service on the data port.
  • A configuration.konghq.com/v1 KongPlugin of type ip-restriction with the allowlist, attached to the TCPIngress via the konghq.com/plugins: ip-whitelist-<release> annotation.
  • An additional ingress rule on the chart’s NetworkPolicy allowing the Kong proxy Pods to reach ValKey.
  • The external hostname is added to the chart-generated TLS certificate’s SAN list so client TLS handshakes succeed.

Kong cluster prerequisites

The chart renders the resources but Kong must be configured to handle them:

  1. Stream listener — Kong proxy needs KONG_STREAM_LISTEN to include a TLS port in ssl_preread mode. Typical config in the Kong Helm release:

    env:
      stream_listen: "0.0.0.0:6379 ssl ssl_preread"
    

    ssl_preread means Kong reads the SNI from ClientHello without terminating TLS; it then forwards the raw encrypted bytes to ValKey, which decrypts. No certificate is configured on the Kong side for that listener.

  2. TCPIngress watching — the Kong Ingress Controller must be configured to watch TCPIngress resources. This is on by default in KIC ≥ 2.0.

  3. DNS — point valkey.example.com at Kong’s external LB, using the same record pattern as your other services.

  4. Cluster-mode caveat — TCPIngress routes to a single Service. In cluster mode, the primary Service load-balances across cluster Pods, which is fine for the data port (any Pod redirects via MOVED), but clients must be cluster-aware. Sentinel-aware clients should NOT route writes via Kong/TCPIngress — use a Sentinel SDK over the cross-namespace path instead.

Client connection (external)

valkey-cli --tls \
  --cacert /path/to/valkey-ca.crt \
  -h valkey.example.com \
  -p 6379 \
  -a "$VALKEY_PASSWORD" \
  PING

Self-signed cert generated by the chart has the external hostname in its SAN list, so client cert verification just works. If you prefer a publicly trusted cert, set tls.existingSecret to a cert-manager-issued Secret whose cert covers exposure.external.host.

Disabling

exposure:
  external:
    enabled: false

The TCPIngress + KongPlugin are removed on helm upgrade. The auto-added NP rule for Kong is removed too. ValKey reverts to in-cluster-only reachability.

Manual escape hatch — raw peer entries

For anything not covered by the shortcuts (IP blocks, label-AND-podSelector combinations, cross-cluster CIDRs), use networkPolicy.allowFrom. Entries keep the familiar Kubernetes NetworkPolicyPeer shape (ipBlock / namespaceSelector / podSelector) and the chart translates each one into an equivalent Calico source rule (ipBlock → nets/notNets, selectors → Calico selector expressions):

networkPolicy:
  allowFrom:
    - ipBlock:
        cidr: 10.42.0.0/16
        except:
          - 10.42.99.0/24
    - namespaceSelector:
        matchLabels:
          tier: trusted
      podSelector:
        matchLabels:
          allowed-to-talk-to-valkey: "true"

Each entry is rendered as one additional Calico ingress rule (source: + destination.ports) covering the data port (and sentinel/metrics ports as relevant).

Debugging “I can’t reach ValKey”

Walk the path in order:

  1. DNS — kubectl exec -n <caller-ns> <pod> -- nslookup vk-valkey.<valkey-ns>.svc.cluster.local. If DNS fails, the chart’s Services aren’t matching Pods — check Pod labels.
  2. Network reachability — kubectl exec -n <caller-ns> <pod> -- nc -zv vk-valkey.<valkey-ns>.svc.cluster.local 6379. If this hangs, a NetworkPolicy is dropping packets.
  3. Confirm caller’s egress — the caller’s namespace may have its own egress-restricting policy. kubectl get netpol -n <caller-ns>.
  4. Confirm ValKey’s ingress — kubectl describe netpol -n <valkey-ns> vk-valkey. The Allowing ingress traffic: section lists every accepted source. Cross-reference the caller’s labels.
  5. TLS — if connection establishes but valkey-cli returns unable to verify or bad handshake, the caller’s CA bundle is wrong. Mount the chart’s <release>-tls-ca ConfigMap (ca.crt).
  6. Auth — WRONGPASS means password mismatch; NOAUTH means auth is on but the client didn’t send a password.