#################################################### # App Deployment with OPA-Envoy and Envoy sidecars. #################################################### apiVersion: apps/v1 kind: Deployment metadata: name: example-app labels: app: example-app spec: replicas: 1 selector: matchLabels: app: example-app template: metadata: labels: app: example-app spec: initContainers: - name: proxy-init image: openpolicyagent/proxy_init:v8 # Configure the iptables bootstrap script to redirect traffic to the # Envoy proxy on port 8000, specify that Envoy will be running as user # 1111, and that we want to exclude port 8282 from the proxy for the # OPA health checks. These values must match up with the configuration # defined below for the "envoy" and "opa" containers. args: ["-p", "8000", "-u", "1111", "-w", "8282"] securityContext: capabilities: add: - NET_ADMIN runAsNonRoot: false runAsUser: 0 containers: - name: app image: openpolicyagent/demo-test-server:v1 ports: - containerPort: 8080 - name: envoy image: envoyproxy/envoy:v1.10.0 securityContext: runAsUser: 1111 volumeMounts: - readOnly: true mountPath: /config name: proxy-config args: - "envoy" - "--config-path" - "/config/envoy.yaml" - name: opa-envoy image: openpolicyagent/opa:latest-envoy securityContext: runAsUser: 1111 volumeMounts: - readOnly: true mountPath: /policy name: opa-policy - readOnly: true mountPath: /config name: opa-envoy-config args: - "run" - "--server" - "--config-file=/config/config.yaml" - "--addr=localhost:8181" - "--diagnostic-addr=0.0.0.0:8282" - "--ignore=.*" - "/policy/policy.rego" livenessProbe: httpGet: path: /health?plugins scheme: HTTP port: 8282 initialDelaySeconds: 5 periodSeconds: 5 readinessProbe: httpGet: path: /health?plugins scheme: HTTP port: 8282 initialDelaySeconds: 5 periodSeconds: 5 volumes: - name: proxy-config configMap: name: proxy-config - name: opa-policy configMap: name: opa-policy - name: opa-envoy-config configMap: name: opa-envoy-config --- ############################################################ # Example configuration to bootstrap OPA-Envoy sidecars. ############################################################ apiVersion: v1 kind: ConfigMap metadata: name: opa-envoy-config data: config.yaml: | plugins: envoy_ext_authz_grpc: addr: :9191 path: envoy/authz/allow decision_logs: console: true --- ###################################################################### # Envoy Config with External Authorization filter that will query OPA. ###################################################################### apiVersion: v1 kind: ConfigMap metadata: name: proxy-config data: envoy.yaml: | static_resources: listeners: - address: socket_address: address: 0.0.0.0 port_value: 8000 filter_chains: - filters: - name: envoy.http_connection_manager typed_config: "@type": type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager codec_type: auto stat_prefix: ingress_http route_config: name: local_route virtual_hosts: - name: backend domains: - "*" routes: - match: prefix: "/" route: cluster: service http_filters: - name: envoy.ext_authz typed_config: "@type": type.googleapis.com/envoy.config.filter.http.ext_authz.v2.ExtAuthz with_request_body: max_request_bytes: 8192 allow_partial_message: true failure_mode_allow: false grpc_service: google_grpc: target_uri: 127.0.0.1:9191 stat_prefix: ext_authz timeout: 0.5s - name: envoy.router typed_config: {} clusters: - name: service connect_timeout: 0.25s type: strict_dns lb_policy: round_robin load_assignment: cluster_name: service endpoints: - lb_endpoints: - endpoint: address: socket_address: address: 127.0.0.1 port_value: 8080 admin: access_log_path: "/dev/null" address: socket_address: address: 0.0.0.0 port_value: 8001 --- ############################################################ # Example policy to enforce into OPA-Envoy sidecars. ############################################################ apiVersion: v1 kind: ConfigMap metadata: name: opa-policy data: policy.rego: | package envoy.authz import input.attributes.request.http as http_request default allow = false token = {"valid": valid, "payload": payload} { [_, encoded] := split(http_request.headers.authorization, " ") [valid, _, payload] := io.jwt.decode_verify(encoded, {"secret": "secret"}) } allow { is_token_valid action_allowed } is_token_valid { token.valid now := time.now_ns() / 1000000000 token.payload.nbf <= now now < token.payload.exp } action_allowed { http_request.method == "GET" token.payload.role == "guest" glob.match("/people*", [], http_request.path) } action_allowed { http_request.method == "GET" token.payload.role == "admin" glob.match("/people*", [], http_request.path) } action_allowed { http_request.method == "POST" token.payload.role == "admin" glob.match("/people", [], http_request.path) lower(input.parsed_body.firstname) != base64url.decode(token.payload.sub) }