Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
name: Post Merge
name: Checks

on:
push:
branches:
- master
pull_request:
branches:
- master

jobs:
go-build:
Expand Down Expand Up @@ -41,6 +44,7 @@ jobs:

deploy:
name: Push Latest Release
if: github.ref == 'refs/heads/master' # only true for pushes to `master`
runs-on: ubuntu-18.04
steps:
- name: Check out code
Expand All @@ -57,7 +61,7 @@ jobs:
run: make deploy-ci

e2e:
name: End-to-End Test
name: Istio End-to-End Test
runs-on: ubuntu-18.04
steps:
- name: Check out code
Expand Down Expand Up @@ -86,3 +90,26 @@ jobs:

- name: Cleanup
run: kind delete cluster

e2e-envoy-grpc:
name: Envoy gRPC End-to-End Test
runs-on: ubuntu-18.04
steps:
- name: Check out code
uses: actions/checkout@v2

- name: Build docker image
run: make image tag-latest

- name: Build testsrv docker image
run: make testsrv-image
working-directory: examples/grpc

- name: Run test
run: make test-setup test
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this could be flakey. test-setup run docker-compose up -d, and the tests start calling the service; there's a chance that envoy isn't ready yet.

However, I haven't been able to trigger this so far locally,

$ docker-compose up -d; grpcurl -plaintext -protoset testsrv.pb 127.0.0.1:51051 test.KitchenSink/Ping
Creating network "grpc_default" with the default driver
Creating grpc_envoy_1     ... done
Creating grpc_testsrv_1   ... done
Creating grpc_opa-envoy_1 ... done
{

}
$

and on github, we're more than likely to pull down the grpcurl image anyways, given envoy plenty of time. While I'm not happy with this arrangement, let's try to roll with it. We'll deal with it if it becomes a problem.

working-directory: examples/grpc

- name: Run test log dump and cleanup
run: make test-teardown
if: ${{ always() }}
working-directory: examples/grpc
68 changes: 0 additions & 68 deletions .github/workflows/pull-request.yaml

This file was deleted.

7 changes: 7 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,13 @@ check-vet:
check-lint:
./build/check-lint.sh

generatepb:
protoc --proto_path=test/files \
--descriptor_set_out=test/files/combined.pb \
--include_imports \
test/files/example/Example.proto \
test/files/book/Book.proto

.PHONY: release
release:
docker run $(DOCKER_FLAGS) \
Expand Down
32 changes: 21 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,12 +157,14 @@ volumes:

The OPA-Envoy plugin supports the following configuration fields:

| Field | Required | Description |
| --- | --- | --- |
| `plugins["envoy_ext_authz_grpc"].addr` | No | Set listening address of Envoy External Authorization gRPC server. This must match the value configured in the Envoy config. Default: `:9191`. |
| `plugins["envoy_ext_authz_grpc"].path` | No | Specifies the hierarchical policy decision path. The policy decision can either be a `boolean` or an `object`. If boolean, `true` indicates the request should be allowed and `false` indicates the request should be denied. If the policy decision is an object, it **must** contain the `allowed` key set to either `true` or `false` to indicate if the request is allowed or not respectively. It can optionally contain a `headers` field to send custom headers to the downstream client or upstream. An optional `body` field can be included in the policy decision to send a response body data to the downstream client. Also an optional `http_status` field can be included to send a HTTP response status code to the downstream client other than `403 (Forbidden)`. Default: `envoy/authz/allow`.|
| `plugins["envoy_ext_authz_grpc"].dry-run` | No | Configures the Envoy External Authorization gRPC server to unconditionally return an `ext_authz.CheckResponse.Status` of `google_rpc.Status{Code: google_rpc.OK}`. Default: `false`. |
| `plugins["envoy_ext_authz_grpc"].enable-reflection` | No | Enables gRPC server reflection on the Envoy External Authorization gRPC server. Default: `false`. |

| Field | Required | Description |
| --------------------------------------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `plugins["envoy_ext_authz_grpc"].addr` | No | Set listening address of Envoy External Authorization gRPC server. This must match the value configured in the Envoy config. Default: `:9191`. |
| `plugins["envoy_ext_authz_grpc"].path` | No | Specifies the hierarchical policy decision path. The policy decision can either be a `boolean` or an `object`. If boolean, `true` indicates the request should be allowed and `false` indicates the request should be denied. If the policy decision is an object, it **must** contain the `allowed` key set to either `true` or `false` to indicate if the request is allowed or not respectively. It can optionally contain a `headers` field to send custom headers to the downstream client or upstream. An optional `body` field can be included in the policy decision to send a response body data to the downstream client. Also an optional `http_status` field can be included to send a HTTP response status code to the downstream client other than `403 (Forbidden)`. Default: `envoy/authz/allow`. |
| `plugins["envoy_ext_authz_grpc"].dry-run` | No | Configures the Envoy External Authorization gRPC server to unconditionally return an `ext_authz.CheckResponse.Status` of `google_rpc.Status{Code: google_rpc.OK}`. Default: `false`. |
| `plugins["envoy_ext_authz_grpc"].enable-reflection` | No | Enables gRPC server reflection on the Envoy External Authorization gRPC server. Default: `false`. |
| `plugins["envoy_ext_authz_grpc"].proto-descriptor` | No | Set the path to a pb that enables the capability to decode the raw body to the parsed body. Default: turns this capability off. |

If the configuration does not specify the `path` field, `envoy/authz/allow` will be considered as the default policy
decision path. `data.envoy.authz.allow` will be the name of the policy decision to query in the default case.
Expand All @@ -175,6 +177,14 @@ The `enable-reflection` parameter registers the Envoy External Authorization gRP
server reflection, a command line tool such as [grpcurl](https://github.com/fullstorydev/grpcurl) can be used to invoke
RPC methods on the gRPC server. See [gRPC Server Reflection Usage](#grpc-server-reflection-usage) section for more details.

Providing a file containing a protobuf descriptor set allows the plugin to decode gRPC message payloads.
So far, only unary methods using uncompressed protobuf-encoded payloads are supported.
The protoset can be generated using `protoc`, e.g. `protoc --descriptor_set_out=protoset.pb --include_imports`.

Note that gRPC message payload decoding is only available [using the v3 API](#envoy-xds-v2-and-v2).
See [`examples/grpc`](examples/grpc) for an example setup using Envoy, a gRPC service, and opa-envoy-plugin examining the
request payloads.

An example of a rule that returns an object that not only indicates if a request is allowed or not but also provides
optional response headers, body and HTTP status that can be sent to the downstream client or upstream can be seen below
in the [Example Policy with Object Response](#example-policy-with-object-response) section.
Expand All @@ -198,11 +208,11 @@ bundles:
envoy/authz:
service: controller
plugins:
envoy_ext_authz_grpc:
addr: :9191
path: envoy/authz/allow
dry-run: false
enable-reflection: false
envoy_ext_authz_grpc:
addr: :9191
path: envoy/authz/allow
dry-run: false
enable-reflection: false
```

You can download the bundle and inspect it yourself:
Expand Down
29 changes: 29 additions & 0 deletions examples/grpc/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
SHELL:=bash
GRPCURL_IMAGE:=fullstorydev/grpcurl:v1.7.0
GRPCURL=docker run --network=host -i --rm -v $$(pwd)/testsrv.pb:/testsrv.pb $(GRPCURL_IMAGE) \
-d @ -plaintext -protoset /testsrv.pb 127.0.0.1:51051

all: testsrv.pb testsrv-image test-setup test test-teardown

.PHONY: testsrv-image
testsrv-image:
docker build -t testsrv testsrv/

testsrv.pb: testsrv/test.proto
protoc --include_imports -o "$@" "$<"

.PHONY: test-setup
test-setup:
docker-compose up -d

.PHONY: test-teardown
test-teardown:
docker-compose logs
docker-compose down

.PHONY: test
test:
$(GRPCURL) test.KitchenSink/Ping <<<"{}"
$(GRPCURL) test.KitchenSink/Exchange < message.json
if sed s/alice/arno/ message.json | $(GRPCURL) test.KitchenSink/Exchange; then \
echo "expected 'Permission Denied'"; exit 1; fi
82 changes: 82 additions & 0 deletions examples/grpc/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Envoy and gRPC example

The docker-compose.yaml file defines three services:
1. testsrv, a gRPC server used for testing, created by [fullstorydev](https://github.com/fullstorydev/grpcui/tree/master/testing/cmd/testsvr)
2. opa-envoy-plugin, equipped with the descriptor set for testsrv
3. Envoy, configured to use opa-envoy-plugin as ext_authz service, using the v3 API,
and including the request payloads _as bytes_:
```yaml
- name: envoy.ext_authz
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz
transport_api_version: V3
failure_mode_allow: false
grpc_service:
envoy_grpc:
cluster_name: opa-envoy
with_request_body:
allow_partial_message: true
max_request_bytes: 1024
pack_as_bytes: true
```

After spinning them up with `docker-compose up`, they can be exercised
using a gRPC client.

This is an example invocation using `grpcurl`:

```interactive
$ grpcurl -plaintext -protoset testsrv.pb 127.0.0.1:51051 test.KitchenSink/Ping
{

}
$ grpcurl -plaintext -protoset testsrv.pb 127.0.0.1:51051 test.KitchenSink/Exchange
ERROR:
Code: PermissionDenied
Message:
$ grpcurl -d @ -plaintext -protoset testsrv.pb 127.0.0.1:51051 test.KitchenSink/Exchange < message.json
{
"person": {
"id": "123",
"name": "alice",
"parent": {
"id": "122",
"name": "bob"
}
},
"state": "AWAITING_INPUT",
"neededNumA": 1.23,
"neededNumB": 1.23,
"opaqueId": "asdf",
"wk": {
"now": "2020-12-02T09:48:42.118723Z",
"period": "30s",
"neat": {
"@type": "googleapis.com/google.protobuf.StringValue",
"value": "Hithere"
},
"object": {
"foo": "bar"
},
"value": "string",
"list": [
"zero",
"one",
"infinity"
],
"bytes": "AAAA",
"string": "abcd",
"bool": true,
"double": 0.12,
"float": 0.12,
"smallInt": 1,
"bigInt": "2",
"smallId": 100,
"bigId": "101"
}
}
```

The policy used in this example, `policy.rego`, is quite artificial, but allows us
to show how different protobuf fields are going to look like when made available to
OPA. The service definition used can be found in `testsrv/test.proto`.
26 changes: 26 additions & 0 deletions examples/grpc/docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
version: '3'
services:
envoy:
image: envoyproxy/envoy:v1.16-latest
ports:
- "9901:9901"
- "51051:51051"
volumes:
- ./envoy.yaml:/etc/envoy/envoy.yaml
opa-envoy:
image: openpolicyagent/opa:latest-envoy
ports:
- "9191:9191"
command:
- run
- --server
- --config-file=/opa.yaml
- /policy.rego
volumes:
- ./testsrv.pb:/testsrv.pb
- ./policy.rego:/policy.rego
- ./opa.yaml:/opa.yaml
testsrv:
image: testsrv:latest
ports:
- "9090:9090"
Loading