OpenDRR / pygeoapi

pygeoapi is a Python server implementation of the OGC API suite of standards. The project emerged as part of the next generation OGC API efforts in 2018 and provides the capability for organizations to deploy a RESTful OGC API endpoint using OpenAPI, GeoJSON, and HTML. pygeoapi is open source and released under an MIT license.
https://pygeoapi.io
MIT License
0 stars 1 forks source link

Ability to set optional SSL certs for Gunicorn #19

Closed arashmalekz closed 2 years ago

arashmalekz commented 2 years ago

Gunicorn can be started with SSL certs using two additional parameters.

--certfile=/certs/tls.crt --keyfile=/certs/tls.key

The call to start Gunicorn is in docker/entrypoint.sh. The value for these parameters can be provided as environment variables. The code needs to be updated to include certfile and keyfile parameters only if they're available as environment variables.

anthonyfok commented 2 years ago

@arashmalekz, Great discovery and great plan! Thank you for headstarting it for me!

The call to start Gunicorn is in docker/entrypoint.sh. The value for these parameters can be provided as environment variables. The code needs to be updated to include certfile and keyfile parameters only if they're available as environment variables.

These are the lines in docker/entrypoint.sh that @arashmalekz are referring to:

https://github.com/OpenDRR/pygeoapi/blob/1ab04458c4db135592be1738cc5e74c1212258a4/docker/entrypoint.sh#L104-L110

I am totally new to Gunicorn, and quite rusty on SSL certificates, so I'll start by researching and documenting here in this comment. Please correct me if you see anything wrong.

Questions and Answers

What is Gunicorn?

From https://gunicorn.org/:

Gunicorn 'Green Unicorn' is a Python WSGI HTTP Server for UNIX. It's a pre-fork worker model. The Gunicorn server is broadly compatible with various web frameworks, simply implemented, light on server resources, and fairly speedy.

How to get a bash prompt for the pygeoapi container (for looking around and testing)?

docker run -it --entrypoint /bin/bash ghcr.io/opendrr/pygeoapi:latest

Credit: https://gist.github.com/mitchwongho/11266726#gistcomment-1996725

How to access the certs from inside Docker?

Use Docker volumes. The top answer at https://stackoverflow.com/questions/43642601/running-gunicorn-with-ssl-on-localhost-with-docker

-v /path/to/tls.crt:/certs/tls.crt:ro -v /path/to/tls.key:/certs/tls.key:ro -v /path/to/ca.crt:/certs/ca.cert:ro

What are new to me and especially impress me are:

  1. These are single-file volumes! I thought they had to be directories, but single files work too, for improved security.
  2. The :ro read-only suffix prevents modification to the SSL certificate/key/CA files from the pygeoapi container, for extra security! Super!

What should I name the two variables for storing the paths to tls.crt and tls.key?

Good question! I haven't decided yet. We'll see in the pull request. 😁

Gunicorn SSL settings documentation

Gunicorn SSL parameters such as --certfile=/certs/tls.crt --keyfile=/certs/tls.key are documented at:

How to generate a self-signed SSL certificate for testing?

See https://devcenter.heroku.com/articles/ssl-certificate-self, which gives the following instruction:

openssl genrsa -aes256 -passout pass:gsahdg -out server.pass.key 4096
openssl rsa -passin pass:gsahdg -in server.pass.key -out server.key
rm server.pass.key
openssl req -new -key server.key -out server.csr
openssl x509 -req -sha256 -days 365 -in server.csr -signkey server.key -out server.crt

Background information

The idea to serve pygeoapi over HTTPS came up during the GSC Cloud tech meeting on December 29, 2021.

While https://demo.pygeoapi.io/ from https://github.com/geopython/demo.pygeoapi.io uses traefik as an edge/proxy server routing incoming HTTPS (see how to set user-defined TLS at https://doc.traefik.io/traefik/https/tls/), that is another container (e.g. traefik:1.7.10-alpine) that needs to be run, and not quite a complete end-to-end encryption. So, in our use case, it is desirable to have the SSL encryption handled by Gunicorn itself.

arashmalekz commented 2 years ago

@anthonyfok I tested this using GUNICORN_CMD_ARGS as you suggested and it worked great. This issue can be closed. Thanks!

anthonyfok commented 2 years ago

@arashmalekz Thank you so much for your feedback!

BTW, I did go ahead and finished PR #20:

... more as an exercise and as documentation for myself, and probably something to approach the upstream project with and see if they would be interested in having HTTPS support documented in their official manual or wiki, for example.

And, finally, for the sake of documentation, this is how to one might use GUNICORN_CMD_ARGS to get pygeoapi to serve over HTTPS:

docker run -p 5000:80 \
    -e GUNICORN_CMD_ARGS="--certfile=/certs/tls.crt --keyfile=/certs/tls.key" \
    -v /path/to/tls.crt:/certs/tls.crt:ro -v /path/to/tls.key:/certs/tls.key:ro \
    -v $(pwd)/my.config.yml:/pygeoapi/local.config.yml \
    -it ghcr.io/opendrr/pygeoapi:latest

where url: http://localhost:5000 is changed to url: https://localhost:5000 is set in the server section in my.config.yml