Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

examples: Add double proxy sandbox #13748

Merged
merged 30 commits into from
Nov 10, 2020
Merged
Show file tree
Hide file tree
Changes from 25 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
174 changes: 174 additions & 0 deletions docs/root/start/sandboxes/double-proxy.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
.. _install_sandboxes_double_proxy:

Double proxy (with encryption)
==============================

This sandbox demonstrates a basic "double proxy" configuration, in which a simple Flask app
connects to a PostgreSQL database, with two Envoy proxies in between.

``Envoy (front)`` -> ``Flask`` -> ``Envoy (postgres-front)`` -> ``Envoy (postgres-back)`` -> ``PostgreSQL``

This type of setup is common in a service mesh where Envoy acts as a "sidecar" between individual services.

It can also be useful as a way of providing access for application servers to upstream services or
databases that may be in a different location or subnet, outside of a service mesh or sidecar-based setup.

Another common use case is with Envoy configured to provide "Points of presence" at the edges of the cloud,
and to relay requests to upstream servers and services.

This example encrypts the transmission of data between the two middle proxies, using ``mTLS``. The proxies
also validate and authenticate each others certificates.

This can be useful if the proxies are physically separated or transmit data over untrusted networks.

In order to use the sandbox you will first need to generate the necessary SSL keys and certificates.

This example walks through creating a certificate authority, and using it to create a domain key and sign
certificates for the proxyies.
phlax marked this conversation as resolved.
Show resolved Hide resolved

.. include:: _include/docker-env-setup.rst

Change to the ``examples/double-proxy`` directory.

Step 3: Create a certificate authority
**************************************

First create a key for the certificate authority:

.. code-block:: console

$ pwd
envoy/examples/double-proxy
$ mkdir -p certs
$ openssl genrsa -out certs/ca.key 4096
Generating RSA private key, 4096 bit long modulus (2 primes)
..........++++
..........................................................................................................++++
e is 65537 (0x010001)

Now use the key to generate a certificate authority certificate.

If you wish, you can interactively alter the fields in the certificate.

For the purpose of this example, the defaults should be sufficient.

.. code-block:: console

$ openssl req -x509 -new -nodes -key certs/ca.key -sha256 -days 1024 -out certs/ca.crt

You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:
State or Province Name (full name) [Some-State]:
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:
Email Address []:

Step 4: Create a domain key
***************************

Create a key for the example domain:
phlax marked this conversation as resolved.
Show resolved Hide resolved

.. code-block:: console

$ openssl genrsa -out certs/example.com.key 2048
Generating RSA private key, 2048 bit long modulus (2 primes)
..+++++
.................................................+++++
e is 65537 (0x010001)

Step 5: Generate certificate signing requests for the proxies
*************************************************************

Use the domain key to generate certificate signing requests for each of the proxies:

.. code-block:: console

$ openssl req -new -sha256 \
-key certs/example.com.key \
-subj "/C=US/ST=CA/O=MyExample, Inc./CN=proxy-postgres-frontend.example.com" \
-out certs/proxy-postgres-frontend.example.com.csr
$ openssl req -new -sha256 \
-key certs/example.com.key \
-subj "/C=US/ST=CA/O=MyExample, Inc./CN=proxy-postgres-backend.example.com" \
-out certs/proxy-postgres-backend.example.com.csr

Step 6: Sign the proxy certificates
***********************************

You can now use the certificate authority that you created to sign the certificate requests:
phlax marked this conversation as resolved.
Show resolved Hide resolved

Note the ``subjectAltName``. This is used for reciprocally matching and validating the certificates.
phlax marked this conversation as resolved.
Show resolved Hide resolved

.. code-block:: console

$ openssl x509 -req \
-in certs/proxy-postgres-frontend.example.com.csr \
-CA certs/ca.crt \
-CAkey certs/ca.key \
-CAcreateserial \
-extfile <(printf "subjectAltName=DNS:proxy-postgres-frontend.example.com") \
phlax marked this conversation as resolved.
Show resolved Hide resolved
-out certs/postgres-frontend.example.com.crt \
-days 500 \
-sha256
Signature ok
subject=C = US, ST = CA, O = "MyExample, Inc.", CN = proxy-postgres-frontend.example.com
Getting CA Private Key

$ openssl x509 -req \
-in certs/proxy-postgres-backend.example.com.csr \
-CA certs/ca.crt \
-CAkey certs/ca.key \
-CAcreateserial \
-extfile <(printf "subjectAltName=DNS:proxy-postgres-backend.example.com") \
-out certs/postgres-backend.example.com.crt \
-days 500 \
-sha256
Signature ok
subject=C = US, ST = CA, O = "MyExample, Inc.", CN = proxy-postgres-backend.example.com
Getting CA Private Key

At this point you should have the necessary keys and certificates to secure the connection between
the proxies.

They keys and certificates are stored in the ``certs/`` directory.

Step 7: Start all of our containers
***********************************

Build and start the containers.

This will load the required keys and certificates into the frontend and backend proxies.

.. code-block:: console

$ pwd
envoy/examples/double-proxy
$ docker-compose build --pull
$ docker-compose up -d
$ docker-compose ps

Name Command State Ports
--------------------------------------------------------------------------------------------------------
double-proxy_app_1 python3 /code/service.py Up
double-proxy_postgres_1 docker-entrypoint.sh postgres Up 5432/tcp
double-proxy_proxy-frontend_1 /docker-entrypoint.sh /usr ... Up 0.0.0.0:10000->10000/tcp
double-proxy_proxy-postgres-backend_1 /docker-entrypoint.sh /usr ... Up 10000/tcp
double-proxy_proxy-postgres-frontend_1 /docker-entrypoint.sh /usr ... Up 10000/tcp

Step 8: Check the flask app can connect to the database
*******************************************************

Checking the response at http://localhost:10000, you should see the output from the Flask app:

.. code-block:: console

$ curl http://localhost:10000
phlax marked this conversation as resolved.
Show resolved Hide resolved
Connected to Postgres, version: PostgreSQL 13.0 (Debian 13.0-1.pgdg100+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 8.3.0-6) 8.3.0, 64-bit
1 change: 1 addition & 0 deletions docs/root/start/sandboxes/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ features. The following sandboxes are available:
cache
cors
csrf
double-proxy
dynamic-configuration-filesystem
dynamic-configuration-control-plane
ext_authz
Expand Down
7 changes: 7 additions & 0 deletions examples/double-proxy/Dockerfile-app
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
FROM python:3.8-alpine

RUN apk update && apk add postgresql-dev gcc python3-dev musl-dev
RUN pip3 install -q Flask==0.11.1 requests==2.18.4 psycopg2-binary
RUN mkdir /code
ADD ./service.py /code
ENTRYPOINT ["python3", "/code/service.py"]
5 changes: 5 additions & 0 deletions examples/double-proxy/Dockerfile-proxy
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
FROM envoyproxy/envoy-dev:latest

COPY ./envoy.yaml /etc/envoy.yaml
RUN chmod go+r /etc/envoy.yaml
CMD ["/usr/local/bin/envoy", "-c /etc/envoy.yaml", "-l", "debug"]
9 changes: 9 additions & 0 deletions examples/double-proxy/Dockerfile-proxy-backend
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
FROM envoyproxy/envoy-dev:latest

COPY ./envoy-backend.yaml /etc/envoy.yaml
COPY ./certs/ca.crt /certs/cacert.pem
COPY ./certs/postgres-backend.example.com.crt /certs/servercert.pem
COPY ./certs/example.com.key /certs/serverkey.pem

RUN chmod go+r /etc/envoy.yaml /certs/cacert.pem /certs/serverkey.pem /certs/servercert.pem
CMD ["/usr/local/bin/envoy", "-c /etc/envoy.yaml", "-l", "debug"]
9 changes: 9 additions & 0 deletions examples/double-proxy/Dockerfile-proxy-frontend
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
FROM envoyproxy/envoy-dev:latest

COPY ./envoy-frontend.yaml /etc/envoy.yaml
COPY ./certs/ca.crt /certs/cacert.pem
COPY ./certs/postgres-frontend.example.com.crt /certs/clientcert.pem
COPY ./certs/example.com.key /certs/clientkey.pem

RUN chmod go+r /etc/envoy.yaml /certs/cacert.pem /certs/clientkey.pem /certs/clientcert.pem
CMD ["/usr/local/bin/envoy", "-c /etc/envoy.yaml", "-l", "debug"]
2 changes: 2 additions & 0 deletions examples/double-proxy/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
To learn about this sandbox and for instructions on how to run it please head over
to the [Envoy docs](https://www.envoyproxy.io/docs/envoy/latest/start/sandboxes/double-proxy.html).
66 changes: 66 additions & 0 deletions examples/double-proxy/docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
version: "3.7"
services:

proxy-frontend:
build:
context: .
dockerfile: Dockerfile-proxy
networks:
edge:
ports:
- "10000:10000"

app:
build:
context: .
dockerfile: Dockerfile-app
networks:
edge:
postgres-frontend:

proxy-postgres-frontend:
build:
context: .
dockerfile: Dockerfile-proxy-frontend
networks:
postgres-frontend:
aliases:
- postgres
postgres-in-between:
aliases:
- proxy-postgres-frontend.example.com
phlax marked this conversation as resolved.
Show resolved Hide resolved

proxy-postgres-backend:
build:
context: .
dockerfile: Dockerfile-proxy-backend
networks:
postgres-backend:
postgres-in-between:
aliases:
- proxy-postgres-backend.example.com

postgres:
image: postgres:latest
networks:
postgres-backend:
environment:
# WARNING! Do not use it on production environments because this will
# allow anyone with access to the Postgres port to access your
# database without a password, even if POSTGRES_PASSWORD is set.
# See PostgreSQL documentation about "trust":
# https://www.postgresql.org/docs/current/auth-trust.html
POSTGRES_HOST_AUTH_METHOD: trust

networks:
edge:
name: edge

postgres-backend:
name: postgres-backend

postgres-frontend:
name: postgres-frontend

postgres-in-between:
name: postgres-in-between
54 changes: 54 additions & 0 deletions examples/double-proxy/envoy-backend.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
static_resources:
listeners:
- name: postgres_listener
address:
socket_address:
address: 0.0.0.0
port_value: 5432
listener_filters:
- name: "envoy.filters.listener.tls_inspector"
typed_config: {}
filter_chains:
- filters:
- name: envoy.filters.network.postgres_proxy
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.postgres_proxy.v3alpha.PostgresProxy
stat_prefix: egress_postgres
- name: envoy.filters.network.tcp_proxy
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy
stat_prefix: postgres_tcp
cluster: postgres_cluster
filter_chain_match:
server_names:
- proxy-postgres-backend.example.com
phlax marked this conversation as resolved.
Show resolved Hide resolved
transport_socket:
name: envoy.transport_sockets.tls
typed_config:
"@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
require_client_certificate: true
common_tls_context:
tls_certificates:
certificate_chain:
filename: certs/servercert.pem
private_key:
filename: certs/serverkey.pem
validation_context:
match_subject_alt_names:
- exact: proxy-postgres-frontend.example.com
trusted_ca:
filename: certs/cacert.pem

clusters:
- name: postgres_cluster
connect_timeout: 1s
type: strict_dns
load_assignment:
cluster_name: postgres_cluster
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: postgres
port_value: 5432
48 changes: 48 additions & 0 deletions examples/double-proxy/envoy-frontend.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
static_resources:
listeners:
- name: postgres_listener
address:
socket_address:
address: 0.0.0.0
port_value: 5432
filter_chains:
- filters:
- name: envoy.filters.network.postgres_proxy
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.postgres_proxy.v3alpha.PostgresProxy
stat_prefix: egress_postgres
- name: envoy.filters.network.tcp_proxy
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy
stat_prefix: postgres_tcp
cluster: postgres_cluster

clusters:
- name: postgres_cluster
connect_timeout: 1s
type: strict_dns
load_assignment:
cluster_name: postgres_cluster
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: proxy-postgres-backend.example.com
port_value: 5432
transport_socket:
name: envoy.transport_sockets.tls
typed_config:
"@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
phlax marked this conversation as resolved.
Show resolved Hide resolved
sni: proxy-postgres-backend.example.com
common_tls_context:
tls_certificates:
certificate_chain:
filename: certs/clientcert.pem
private_key:
filename: certs/clientkey.pem
validation_context:
match_subject_alt_names:
- exact: proxy-postgres-backend.example.com
trusted_ca:
filename: certs/cacert.pem
Loading