diff --git a/dev-environments/grpc/Makefile b/dev-environments/grpc/Makefile new file mode 100644 index 000000000..74552b571 --- /dev/null +++ b/dev-environments/grpc/Makefile @@ -0,0 +1,66 @@ +SHELL = /usr/bin/env bash -o pipefail +.SHELLFLAGS = -ec +.DEFAULT_GOAL := gateway +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +WORKDIR := $(patsubst %/,%,$(dir $(MKFILE_PATH))) +DOCKER ?= $(shell which docker 2> /dev/null || echo "docker") + +gateway: ## run gateway configured to access upstream powered with TLS + $(DOCKER) compose -f docker-compose.yml run --service-ports gateway + +clean: + $(DOCKER) compose down --volumes --remove-orphans + $(DOCKER) compose -f docker-compose.yml down --volumes --remove-orphans + - rm -rf gateway-cert + - rm -rf upstream-cert + - rm -rf bin + +ca: + openssl genrsa -out rootCA.key 2048 + openssl req -batch -new -x509 -nodes -key rootCA.key -sha256 -days 1024 -out rootCA.pem + +clientcerts: + openssl req -subj '/CN=$(DOMAIN)' -newkey rsa:4096 -nodes \ + -sha256 \ + -days 3650 \ + -keyout $(DOMAIN).key \ + -out $(DOMAIN).csr + chmod +r $(DOMAIN).key + openssl x509 -req -in $(DOMAIN).csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out $(DOMAIN).crt -days 500 -sha256 + +$(WORKDIR)/gateway-cert: + mkdir -p gateway-cert + +.PHONY: gateway-certs +gateway-certs: $(WORKDIR)/gateway-cert + $(MAKE) ca -C $(WORKDIR)/gateway-cert -f $(WORKDIR)/Makefile + $(MAKE) clientcerts -C $(WORKDIR)/gateway-cert -f $(WORKDIR)/Makefile DOMAIN=gateway.example.com + +$(WORKDIR)/upstream-cert: + mkdir -p upstream-cert + +.PHONY: upstream-certs +upstream-certs: $(WORKDIR)/upstream-cert + $(MAKE) ca -C $(WORKDIR)/upstream-cert -f $(WORKDIR)/Makefile + $(MAKE) clientcerts -C $(WORKDIR)/upstream-cert -f $(WORKDIR)/Makefile DOMAIN=upstream.example.com + cat $(WORKDIR)/upstream-cert/upstream.example.com.key $(WORKDIR)/upstream-cert/upstream.example.com.crt >$(WORKDIR)/upstream-cert/upstream.example.com.pem + +GRPCURL=$(WORKDIR)/bin/grpcurl +$(GRPCURL): + $(call go-install-tool,$(GRPCURL),github.com/fullstorydev/grpcurl/cmd/grpcurl@v1.8.9) + +.PHONY: grpcurl +grpcurl: $(GRPCURL) ## Download grpcurl locally if necessary. + +# go-install-tool will 'go install' any package $2 and install it to $1. +define go-install-tool +@[ -f $(1) ] || { \ +set -e ;\ +TMP_DIR=$$(mktemp -d) ;\ +cd $$TMP_DIR ;\ +go mod init tmp ;\ +echo "Downloading $(2)" ;\ +GOBIN=$(WORKDIR)/bin go install $(2) ;\ +rm -rf $$TMP_DIR ;\ +} +endef diff --git a/dev-environments/grpc/README.md b/dev-environments/grpc/README.md new file mode 100644 index 000000000..217eda883 --- /dev/null +++ b/dev-environments/grpc/README.md @@ -0,0 +1,52 @@ +# APIcast GRPC endpoint + +## Create the SSL Certificates + +```sh +make gateway-certs +``` + +```sh +make upstream-certs +``` + +## Run the gateway + +Running local `apicast-test` docker image + +```sh +make gateway +``` + +Running custom apicast image + +```sh +make gateway IMAGE_NAME=quay.io/3scale/apicast:latest +``` + +Traffic between the gateway and upstream can be inspected looking at logs from `one.upstream` service + +``` +docker compose -p grpc logs -f one.upstream +``` + +## Testing + + +Get `grpcurl` + +```sh +make grpcurl +``` + +Run request + +```sh +bin/grpcurl -vv -insecure -H "app_id: abc123" -H "app_key: abc123" -authority gateway.example.com 127.0.0.1:8443 main.HelloWorld/Greeting +``` + +## Clean env + +```sh +make clean +``` diff --git a/dev-environments/grpc/apicast-config.json b/dev-environments/grpc/apicast-config.json new file mode 100644 index 000000000..f296dc74d --- /dev/null +++ b/dev-environments/grpc/apicast-config.json @@ -0,0 +1,35 @@ +{ + "services": [ + { + "id": "1", + "backend_version": "2", + "proxy": { + "hosts": ["gateway.example.com"], + "credentials_location": "headers", + "api_backend": "https://one.upstream:443", + "backend": { + "endpoint": "http://127.0.0.1:8081", + "host": "backend" + }, + "policy_chain": [ + { + "name": "apicast.policy.grpc" + }, + { + "name": "apicast.policy.apicast" + } + ], + "proxy_rules": [ + { + "http_method": "POST", + "pattern": "/", + "metric_system_name": "hits", + "delta": 1, + "parameters": [], + "querystring_parameters": {} + } + ] + } + } + ] +} diff --git a/dev-environments/grpc/docker-compose.yml b/dev-environments/grpc/docker-compose.yml new file mode 100644 index 000000000..6e2e62378 --- /dev/null +++ b/dev-environments/grpc/docker-compose.yml @@ -0,0 +1,40 @@ +--- +version: '3.8' +services: + gateway: + image: ${IMAGE_NAME:-apicast-test} + depends_on: + - one.upstream + - two.upstream + environment: + APICAST_HTTPS_PORT: 8443 + APICAST_HTTPS_CERTIFICATE: /var/run/secrets/apicast/gateway.example.com.crt + APICAST_HTTPS_CERTIFICATE_KEY: /var/run/secrets/apicast/gateway.example.com.key + THREESCALE_CONFIG_FILE: /tmp/config.json + THREESCALE_DEPLOYMENT_ENV: staging + APICAST_CONFIGURATION_LOADER: lazy + APICAST_WORKERS: 1 + APICAST_LOG_LEVEL: debug + APICAST_CONFIGURATION_CACHE: "0" + expose: + - "8443" + - "8090" + ports: + - "8443:8443" + - "8090:8090" + volumes: + - ./apicast-config.json:/tmp/config.json + - ./gateway-cert:/var/run/secrets/apicast + one.upstream: + image: alpine/socat:1.7.4.4 + container_name: one.upstream + command: "-v openssl-listen:443,reuseaddr,fork,cert=/etc/pki/upstream.example.com.pem,verify=0,openssl-max-proto-version=TLS1.3 ssl:two.upstream:8005,verify=0" + expose: + - "443" + restart: unless-stopped + volumes: + - ./upstream-cert/upstream.example.com.pem:/etc/pki/upstream.example.com.pem + two.upstream: + image: kalmhq/echoserver + expose: + - "8005"