Skip to content

Instantly share code, notes, and snippets.

@stevenctl
Last active July 2, 2024 15:45
Show Gist options
  • Save stevenctl/ec2ddae79734f8f9367400961ca9c48f to your computer and use it in GitHub Desktop.
Save stevenctl/ec2ddae79734f8f9367400961ca9c48f to your computer and use it in GitHub Desktop.
Static PROXY Waypoint

PROXY Protocol Waypoint

This sample demonstrates a non-Istio waypoint defined using static Envoy config.

  1. Create a kind cluster
kind create cluster
  1. Install Istio with Ambient
istioctl install --set profile=ambient
  1. Enable ambient for the default namespace.
kubectl label namespace default istio.io/dataplane-mode=ambient --overwrite
  1. Deploy sleep as a client
kubectl apply -f samples/sleep/sleep.yaml
  1. Deploy the following manifest.
  • httpbin has istio.io/use-waypoint=static-waypoint
  • static-waypoint is a statically configured Envoy proxy.
  • httpbin-headless just lets us hack around needing EDS for our static envoy.
YAML
cat <<EOF | k apply -f -
---
apiVersion: gateway.networking.k8s.io/v1beta1
kind: GatewayClass
metadata:
  name: static-waypoint
  annotations:
    ambient.istio.io/waypoint-inbound-binding: "PROXY/15088"
spec:
  controllerName: nobody.com/none-controller
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: static-waypoint
spec:
  gatewayClassName: static-waypoint
  listeners:
  - protocol: PROXY
    name: "proxy"
    port: 15088
  # HACK kubectl edit --subresource status gateway static-waypoint and copy these to status
  addresses:
  - type: IPAddress
    value: 10.96.128.128
status:
  addresses:
  - type: IPAddress
    value: 10.96.128.128
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: static-waypoint-config
data:
  envoy.yaml: |-    
    node:
      id: waypoint~0.0.0.0~static-waypoint.default~default.svc.cluster.local
      cluster: inbound-vip|5201|http|iperf-server.default.svc.cluster.local
    admin:
      profile_path: /var/lib/istio/data/envoy.prof
      address:
        socket_address:
          address: 127.0.0.1
          port_value: 15000
      access_log:
        - name: envoy.access_loggers.file
          typed_config:
            '@type': type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
            path: /dev/null
    static_resources:
      listeners:
        - name: inbound_proxy_protocol
          address:
            socket_address:
              address: 0.0.0.0
              port_value: 15088
          listener_filters:
            - name: "proxy_protocol_tlv"
              typed_config:
                '@type': type.googleapis.com/envoy.extensions.filters.listener.proxy_protocol.v3.ProxyProtocol
                allow_requests_without_proxy_protocol: false
                rules:
                - tlv_type: 0xD0
                  on_tlv_present:
                    key: "peer_principal"
                - tlv_type: 0xD1
                  on_tlv_present:
                    key: "hbone_host"
                pass_through_tlvs:
                  match_type: INCLUDE_ALL
          filter_chain_matcher:
                matcher_tree:
                  input:
                    name: destination_ip
                    typed_config:
                      "@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.DestinationIPInput
                  prefix_match_map:
                    map:
                      # TODO we need the actual vip here
                      "10.":
                        action:
                          name: vip
                          typed_config:
                            "@type": type.googleapis.com/google.protobuf.StringValue
                            value: httpbin
          filter_chains:
            - name: httpbin
              filters:
                - name: proxy_protocol_authority
                  typed_config:
                    '@type': type.googleapis.com/envoy.extensions.filters.network.set_filter_state.v3.Config
                    on_new_connection:
                      - object_key: "io.istio.peer_principal"
                        factory_key: "envoy.string"
                        format_string:
                          text_format_source:
                            inline_string: "%DYNAMIC_METADATA(envoy.filters.listener.proxy_protocol:peer_principal)%"
                - name: envoy.filters.network.http_connection_manager
                  typed_config:
                    '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
                    stat_prefix: ingress_http
                    access_log:
                      - name: envoy.access_loggers.stdout
                        typed_config:
                          '@type': type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog
                    http_filters:
                      - name: envoy.filters.http.grpc_stats
                        typed_config:
                          '@type': type.googleapis.com/envoy.extensions.filters.http.grpc_stats.v3.FilterConfig
                          emit_filter_state: true
                          stats_for_all_methods: false
                      - name: envoy.filters.http.fault
                        typed_config:
                          '@type': type.googleapis.com/envoy.extensions.filters.http.fault.v3.HTTPFault
                      - name: envoy.filters.http.cors
                        typed_config:
                          '@type': type.googleapis.com/envoy.extensions.filters.http.cors.v3.Cors
                      - name: envoy.filters.http.router
                        typed_config:
                          '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
                    route_config:
                      name: inbound-vip|8000|http|httpbin.default.svc.cluster.local
                      response_headers_to_add:
                        - header:
                            key: "from-waypoint"
                            value: "static-waypoint"
                      virtual_hosts:
                        - name: inbound|http|8000
                          domains:
                            - '*'
                          routes:
                            - match:
                                prefix: /
                              route:
                                cluster: inbound-vip|8000|http|httpbin.default.svc.cluster.local
                              decorator:
                                operation: :8000/*
                              name: default
      clusters:
        - name: inbound-vip|8000|http|httpbin.default.svc.cluster.local
          type: STRICT_DNS
          load_assignment:
            cluster_name: inbound-vip|8000|http|httpbin.default.svc.cluster.local
            endpoints:
              - lb_endpoints:
                  - endpoint:
                      address:
                        socket_address:
                          address: httpbin-headless.default.svc
                          port_value: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: static-waypoint
spec:
  # HACK static VIP to reference in Gateway
  clusterIP: 10.96.128.128
  ports:
  # HACK this tricks zTunnel into resolving the VIP
  - port: 15008
    name: hbone
    protocol: TCP
  selector:
    app: static-waypoint
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: static-waypoint
spec:
  replicas: 1
  selector:
    matchLabels:
      app: static-waypoint
  template:
    metadata:
      labels:
        app: static-waypoint
        gateway.networking.k8s.io/gateway-name: static-waypoint
    spec:
      nodeName: ambient-control-plane
      containers:
      - name: static-waypoint
        image: localhost:5000/proxyv2:sandwich-test
        command: 
        - envoy
        - --config-path
        - /etc/envoy/envoy.yaml
        - --drain-strategy 
        - immediate
        - --local-address-ip-version
        - v4
        - --file-flush-interval-msec
        - "1000"
        ports:
        - containerPort: 5201
        volumeMounts:
        - name: static-waypoint-config
          mountPath: "/etc/envoy"
      volumes:
      - name: static-waypoint-config
        configMap:
          name: static-waypoint-config
---
#
# httpbin service with static VIP +  a headless version
#
apiVersion: v1
kind: Service
metadata:
  name: httpbin
  labels:
    app: httpbin
    service: httpbin
  annotations:
    istio.io/use-waypoint: static-waypoint
spec:
  # HACK use a static cluster IP that we can reference in envoy config
  clusterIP: 10.96.127.1
  ports:
  - name: http
    port: 8000
    targetPort: 8080
  selector:
    app: httpbin
---
apiVersion: v1
kind: Service
metadata:
  name: httpbin-headless
  labels:
    app: httpbin
    service: httpbin
spec:
  # HACK define a clusterIP service so the static envoy doesn't need EDS
  clusterIP: None
  ports:
  - name: http
    port: 8000
    targetPort: 8080
  selector:
    app: httpbin
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: httpbin
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpbin
spec:
  replicas: 1
  selector:
    matchLabels:
      app: httpbin
      version: v1
  template:
    metadata:
      labels:
        app: httpbin
        version: v1
    spec:
      serviceAccountName: httpbin
      containers:
      - image: docker.io/kong/httpbin
        imagePullPolicy: IfNotPresent
        name: httpbin
        # Same as found in Dockerfile's CMD but using an unprivileged port
        command:
        - gunicorn
        - -b
        - 0.0.0.0:8080
        - httpbin:app
        - -k
        - gevent
        env:
        # Tells pipenv to use a writable directory instead of $HOME
        - name: WORKON_HOME
          value: /tmp
        ports:
        - containerPort: 8080
  EOF
  1. Hack: Set gateway status addressess since we don't have a controller.
kubectl patch --subresource status gateway static-waypoint --type merge --patch '{"status": {"addresses": [{"value":
 "10.96.128.128", "type": "IPAddress"}]}}'
  1. Finally, send traffic. Notice the header from-waypoint.
kubectl exec $(kubectl get po -lapp=sleep -ojsonpath='{.items[0].metadata.name}')  -- curl -sS  httpbin:8000/get -v 
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment