diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 49d5e0bd..24131ee7 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -238,6 +238,7 @@ jobs: - 'http_body' - 'http_config' - 'http_headers' + - 'grpc_auth_random' defaults: run: @@ -301,6 +302,7 @@ jobs: - 'http_body' - 'http_config' - 'http_headers' + - 'grpc_auth_random' defaults: run: diff --git a/README.md b/README.md index d43816d8..53f3de94 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ - [HTTP Headers](./examples/http_headers/) - [HTTP Response body](./examples/http_body/) - [HTTP Configuration](./examples/http_config/) +- [gRPC Auth (random)](./examples/grpc_auth_random/) ## Articles & blog posts from the community diff --git a/examples/grpc_auth_random/Cargo.toml b/examples/grpc_auth_random/Cargo.toml new file mode 100644 index 00000000..fce81040 --- /dev/null +++ b/examples/grpc_auth_random/Cargo.toml @@ -0,0 +1,22 @@ +[package] +publish = false +name = "proxy-wasm-example-grpc-auth-random" +version = "0.0.1" +authors = ["Piotr Sikora "] +description = "Proxy-Wasm plugin example: gRPC auth (random)" +license = "Apache-2.0" +edition = "2018" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +log = "0.4" +proxy-wasm = { path = "../../" } + +[profile.release] +lto = true +opt-level = 3 +codegen-units = 1 +panic = "abort" +strip = "debuginfo" diff --git a/examples/grpc_auth_random/README.md b/examples/grpc_auth_random/README.md new file mode 100644 index 00000000..73978946 --- /dev/null +++ b/examples/grpc_auth_random/README.md @@ -0,0 +1,56 @@ +## Proxy-Wasm plugin example: gRPC auth (random) + +Proxy-Wasm plugin that grants access based on a result of gRPC callout. + +### Building + +```sh +$ cargo build --target wasm32-wasi --release +``` + +### Using in Envoy + +This example can be run with [`docker compose`](https://docs.docker.com/compose/install/) +and has a matching Envoy configuration. + +```sh +$ docker compose up +``` + +#### Access granted. + +Send HTTP request to `localhost:10000/headers`: + +```sh +$ curl localhost:10000/headers +{ + "headers": { + "Accept": "*/*", + "Host": "localhost", + "User-Agent": "curl/7.81.0", + "X-Amzn-Trace-Id": "Root=1-637c4767-6e31776a0b407a0219b5b570", + "X-Envoy-Expected-Rq-Timeout-Ms": "15000" + } +} +``` + +Expected Envoy logs: + +```console +[...] wasm log grpc_auth_random: Access granted. +``` + +#### Access forbidden. + +Send HTTP request to `localhost:10000/headers`: + +```sh +$ curl localhost:10000/headers +Access forbidden. +``` + +Expected Envoy logs: + +```console +[...] wasm log grpc_auth_random: Access forbidden. +``` diff --git a/examples/grpc_auth_random/docker-compose.yaml b/examples/grpc_auth_random/docker-compose.yaml new file mode 100644 index 00000000..a0b61d9d --- /dev/null +++ b/examples/grpc_auth_random/docker-compose.yaml @@ -0,0 +1,45 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +services: + envoy: + image: envoyproxy/envoy:v1.24-latest + hostname: envoy + ports: + - "10000:10000" + volumes: + - ./envoy.yaml:/etc/envoy/envoy.yaml + - ./target/wasm32-wasi/release:/etc/envoy/proxy-wasm-plugins + networks: + - envoymesh + depends_on: + - httpbin + - grpcbin + httpbin: + image: mccutchen/go-httpbin + hostname: httpbin + ports: + - "8080:8080" + networks: + - envoymesh + grpcbin: + image: kong/grpcbin + hostname: grpcbin + ports: + - "9000:9000" + - "9001:9001" + networks: + - envoymesh +networks: + envoymesh: {} diff --git a/examples/grpc_auth_random/envoy.yaml b/examples/grpc_auth_random/envoy.yaml new file mode 100644 index 00000000..a66a16fb --- /dev/null +++ b/examples/grpc_auth_random/envoy.yaml @@ -0,0 +1,82 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +static_resources: + listeners: + address: + socket_address: + address: 0.0.0.0 + port_value: 10000 + filter_chains: + - filters: + - 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 + codec_type: AUTO + route_config: + name: local_routes + virtual_hosts: + - name: local_service + domains: + - "*" + routes: + - match: + prefix: "/" + route: + cluster: httpbin + http_filters: + - name: envoy.filters.http.wasm + typed_config: + "@type": type.googleapis.com/udpa.type.v1.TypedStruct + type_url: type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm + value: + config: + name: "grpc_auth_random" + vm_config: + runtime: "envoy.wasm.runtime.v8" + code: + local: + filename: "/etc/envoy/proxy-wasm-plugins/proxy_wasm_example_grpc_auth_random.wasm" + - name: envoy.filters.http.router + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + clusters: + - name: httpbin + connect_timeout: 5s + type: STRICT_DNS + lb_policy: ROUND_ROBIN + load_assignment: + cluster_name: httpbin + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: httpbin + port_value: 8080 + - name: grpcbin + connect_timeout: 5s + type: STRICT_DNS + lb_policy: ROUND_ROBIN + http2_protocol_options: {} + load_assignment: + cluster_name: grpcbin + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: grpcbin + port_value: 9000 diff --git a/examples/grpc_auth_random/src/lib.rs b/examples/grpc_auth_random/src/lib.rs new file mode 100644 index 00000000..7a1fd5fa --- /dev/null +++ b/examples/grpc_auth_random/src/lib.rs @@ -0,0 +1,61 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use log::info; +use proxy_wasm::traits::*; +use proxy_wasm::types::*; +use std::time::Duration; + +proxy_wasm::main! {{ + proxy_wasm::set_log_level(LogLevel::Trace); + proxy_wasm::set_http_context(|_, _| -> Box { Box::new(GrpcAuthRandom) }); +}} + +struct GrpcAuthRandom; + +impl HttpContext for GrpcAuthRandom { + fn on_http_request_headers(&mut self, _: usize, _: bool) -> Action { + self.dispatch_grpc_call( + "grpcbin", + "grpcbin.GRPCBin", + "RandomError", + vec![], + None, + Duration::from_secs(1), + ) + .unwrap(); + Action::Pause + } + + fn on_http_response_headers(&mut self, _: usize, _: bool) -> Action { + self.set_http_response_header("Powered-By", Some("proxy-wasm")); + Action::Continue + } +} + +impl Context for GrpcAuthRandom { + fn on_grpc_call_response(&mut self, _: u32, status_code: u32, _: usize) { + if status_code % 2 == 0 { + info!("Access granted."); + self.resume_http_request(); + } else { + info!("Access forbidden."); + self.send_http_response( + 403, + vec![("Powered-By", "proxy-wasm")], + Some(b"Access forbidden.\n"), + ); + } + } +}