# k8s/shadowsocks/shadowsocks.yaml
# Personal Shadowsocks proxy (for Shadowrocket/other SS clients) — an
# alternative tunnel to the WireGuard setup in cluster-config/, useful when
# a network blocks/throttles WireGuard but not generic TLS-looking traffic.
#
# Everything that varies between deployments (port, password, method) lives
# in the shadowsocks-config Secret below — the Deployment/Service never
# hardcode a value, so re-pointing this at a new port or rotating the
# password is a Secret edit + rollout restart, no YAML edit.
#
# Prerequisites:
#   talos put cluster/SHADOWSOCKS_PASSWORD SHADOWSOCKS_PASSWORD="$(openssl rand -base64 24)"
#   talos put cluster/SHADOWSOCKS_PORT SHADOWSOCKS_PORT="8388"
#
# Apply:
#   kubectl create namespace vpn --dry-run=client -o yaml | kubectl apply -f -
#   kubectl -n vpn create secret generic shadowsocks-config \
#     --from-literal=SERVER_PORT="$(talos get cluster/SHADOWSOCKS_PORT --key SHADOWSOCKS_PORT)" \
#     --from-literal=PASSWORD="$(talos get cluster/SHADOWSOCKS_PASSWORD --key SHADOWSOCKS_PASSWORD)" \
#     --from-literal=METHOD="aes-256-gcm" \
#     --from-literal=TIMEOUT="300"
#   kubectl apply -f k8s/shadowsocks/shadowsocks.yaml
#
# Rotate password (or change port) later:
#   kubectl -n vpn delete secret shadowsocks-config && <recreate with new values>
#   kubectl -n vpn rollout restart deploy/shadowsocks
#
# Client config: SERVER_PORT/METHOD/PASSWORD above feed directly into the
# Shadowrocket/SS client's server, method, and password fields. SERVER_ADDR
# for the client is the LB IP below (192.168.1.166), or your router's WAN
# address/DDNS hostname (riotpiao.duckdns.org) with port-forwarding to it —
# same pattern as the wg1 WireGuard peer in cluster-config/phone_config.conf.
apiVersion: v1
kind: Namespace
metadata:
  name: vpn

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: shadowsocks
  namespace: vpn
spec:
  replicas: 1
  selector:
    matchLabels:
      app: shadowsocks
  template:
    metadata:
      labels:
        app: shadowsocks
    spec:
      containers:
        - name: shadowsocks
          image: shadowsocks/shadowsocks-libev:latest
          env:
            - name: SERVER_ADDR
              value: "0.0.0.0"
            - name: SERVER_PORT
              valueFrom:
                secretKeyRef:
                  name: shadowsocks-config
                  key: SERVER_PORT
            - name: PASSWORD
              valueFrom:
                secretKeyRef:
                  name: shadowsocks-config
                  key: PASSWORD
            - name: METHOD
              valueFrom:
                secretKeyRef:
                  name: shadowsocks-config
                  key: METHOD
            - name: TIMEOUT
              valueFrom:
                secretKeyRef:
                  name: shadowsocks-config
                  key: TIMEOUT
          # containerPort is informational only (no portRange support for
          # env-driven SERVER_PORT) — the Service below is what actually
          # routes traffic, matched on the same Secret key via downward API
          # isn't available for Service ports, so targetPort uses the literal
          # port name instead; see Service ports comment.
          ports:
            - containerPort: 8388
              protocol: TCP
            - containerPort: 8388
              protocol: UDP
          resources:
            requests:
              cpu: 50m
              memory: 32Mi
            limits:
              cpu: 500m
              memory: 128Mi

---
# LoadBalancer via Cilium LB-IPAM (see k8s/cilium/lb-ipam-pool.yaml) — pinned
# to .166 so router port-forwarding and the DDNS hostname stay stable across
# pod/service recreates, same pattern forgejo uses at .165.
#
# NOTE: SERVER_PORT in the Secret must match port/targetPort/nodePort here.
# If you change the port, update both the Secret and this Service together.
apiVersion: v1
kind: Service
metadata:
  name: shadowsocks
  namespace: vpn
  annotations:
    io.cilium/lb-ipam-ips: "192.168.1.166"
spec:
  type: LoadBalancer
  selector:
    app: shadowsocks
  ports:
    - name: tcp
      protocol: TCP
      port: 8388
      targetPort: 8388
    - name: udp
      protocol: UDP
      port: 8388
      targetPort: 8388

---
# Restrict egress like the forgejo-runner pattern (k8s/forge/runner.yaml) —
# a proxy server is, by design, an open relay to the internet for whoever
# holds the password; LAN/pod-network egress is blocked so a compromised
# password can't be used to pivot into the cluster or LAN. CoreDNS is
# explicitly allowed — shadowsocks-libev resolves client-requested hostnames
# itself, so blanket-blocking the service subnet would break that.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: shadowsocks-egress
  namespace: vpn
spec:
  podSelector:
    matchLabels:
      app: shadowsocks
  policyTypes: [Egress]
  egress:
    - to:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: kube-system
      ports:
        - protocol: UDP
          port: 53
        - protocol: TCP
          port: 53
    - to:
        - ipBlock:
            cidr: 0.0.0.0/0
            except:
              - 192.168.1.0/24
              - 10.244.0.0/16
              - 10.96.0.0/12
