doc: add section on security and misc fixes

Co-authored-by: Roberto Abdelkader Martínez Pérez <robertomartinezp@gmail.com>
This commit is contained in:
pancho horrillo
2019-12-05 18:13:58 +01:00
parent 73ede15929
commit 166c767317
9 changed files with 112 additions and 22 deletions
+33
View File
@@ -0,0 +1,33 @@
Kapow! HTTP Interfaces
======================
`kapow server` sets up three HTTP server interfaces, each with a distinct and
clear purpose.
User Interface
--------------
The User HTTP interface is used to serve final user requests.
By default it binds to address ``0.0.0.0`` and port ``8080``, but can be changed via
the ``--bind`` flag.
Control Interface
-----------------
The Control HTTP interface is used by the command `kapow route` to
administer the list of system routes.
By default it binds to address ``127.0.0.1`` and port ``8081``, but can be changed
via the ``--control-bind`` flag.
Data Interface
--------------
The Data HTTP interface is used by the commands ``kapow get`` and ``kapow
set`` to exchange the data for a particular request.
By default it binds to address ``127.0.0.1`` and port ``8082``, but can be changed
via the ``--data-bind`` flag.
+31
View File
@@ -0,0 +1,31 @@
Philosophy
==========
Single Static Binary
--------------------
- Deployment is then as simple as it gets.
- Docker-friendly.
Shell Agnostic
--------------
- Kapow! knows nothing, and makes no assumptions, about the shell you are using.
It only spawns executables.
- You are free to implement a client to the Data API directly if you are so
inclined. The spec provides all the necessary details.
Not a Silver Bullet
-------------------
You should not use Kapow! if your project requires complex business logic.
If you try to encode business logic in a shell script, you will **deeply**
regret it.
Kapow! is designed for automating simple stuff.
@@ -0,0 +1,62 @@
Request Life Cycle
==================
This section describes the sequence of events happening for each request
answered by the `User HTTP Interface`.
.. image:: ../_static/request_life_cycle.png
1. request
----------
The user makes a request to the `User HTTP Interface`.
- The request is matched against the route table
- ``kapow`` provides a `HANDLER_ID` to identify this request and don't mix it
with other requests that could be running concurrently.
2. spawn
--------
``kapow`` spawns the executable specified as entrypoint in the matching
route.
The default entrypoint is ``/bin/sh``; we'll explain this workflow for now.
The spawned entrypoint is run with the following variables added to its
environment:
- ``KAPOW_HANDLER_ID``: Containing the `HANDLER_ID`
- ``KAPOW_DATAAPI_URL``: With the URL of the `Data HTTP Interface`
- ``KAPOW_CONTROLAPI_URL``: With the URL of the `Control HTTP Interface`
3. ``kapow set /response/body banana``
--------------------------------------
During the lifetime of the shell, the request and response resources are
available via these commands:
- ``kapow get /request/...``
- ``kapow set /response/...``
These commands use the aforementioned environment variables to read data
from the user request and to write the response. They accept data
either as arguments or from ``stdin``.
4. exit
-------
The shell dies.
5. response
-----------
``kapow`` finalizes the original request.
.. todo::
link to resource tree
+353
View File
@@ -0,0 +1,353 @@
The `Kapow!` Resource Tree
==========================
This is the model that Kapow! uses to expose the internals of the user request
being serviced.
We use this tree to get access to any data that comes in the request,
as well as to compose the response.
We access the resource tree easily with the ``kapow set`` and ``kapow get``
subcommands.
Overview
--------
.. code-block:: text
/
├─ request
│ ├──── method Used HTTP Method (GET, POST)
│ ├──── host Host part of the URL
│ ├──── path Complete URL path (URL-unquoted)
│ ├──── matches
│ │ └──── <name> Previously matched URL path parts
│ ├──── params
│ │ └──── <name> URL parameters (after the "?" symbol)
│ ├──── headers
│ │ └──── <name> HTTP request headers
│ ├──── cookies
│ │ └──── <name> HTTP request cookie
│ ├──── form
│ │ └──── <name> Value of the form field with name <name>
│ ├──── files
│ │ └──── <name>
│ │ └──── filename Original file name of the file uploaded in the form field <name>
│ │ └──── content The contents of the file uploaded in the form field <name>
│ └──── body HTTP request body
└─ response
├──── status HTTP status code
├──── headers
│ └──── <name> HTTP response headers
├──── cookies
│ └──── <name> HTTP request cookie
└──── body Response body
Resources
---------
``/request/method`` Resource
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The HTTP method of the incoming request.
**Sample Usage**
If the user runs:
.. code-block:: bash
$ curl -X POST http://kapow.example:8080
then, when handling the request:
.. code-block:: bash
$ kapow get /request/method
POST
``/request/host`` Resource
~~~~~~~~~~~~~~~~~~~~~~~~~~
The ``Host`` header as defined in the HTTP/1.1 spec of the incoming
request.
**Sample Usage**
If the user runs:
.. code-block:: bash
$ curl http://kapow.example:8080
then, when handling the request:
.. code-block:: bash
$ kapow get /request/host
kapow.example
``/request/path`` Resource
~~~~~~~~~~~~~~~~~~~~~~~~~~
Contains the path substring of the URL.
**Sample Usage**
If the user runs:
.. code-block:: bash
$ curl http://kapow.example:8080/foo/bar?qux=1
then, when handling the request:
.. code-block:: bash
$ kapow get /request/path
/foo/bar
``/request/matches/<name>`` Resource
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Contains the part of the URL captured by the pattern ``name``.
**Sample Usage**
For a route defined like this:
.. code-block:: bash
$ kapow route add /foo/{mymatch}/bar
if the user runs:
.. code-block:: bash
$ curl http://kapow.example:8080/foo/1234/bar
then, when handling the request:
.. code-block:: bash
$ kapow get /request/matches/mymatch
1234
``/request/params/<name>`` Resource
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Contains the value of the URL parameter ``name``
**Sample Usage**
If the user runs:
.. code-block:: bash
$ curl http://kapow.example:8080/foo?myparam=bar
then, when handling the request:
.. code-block:: bash
$ kapow get /request/params/myparam
myparam
``/request/headers/<name>`` Resource
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Contains the value of the HTTP header ``name`` of the incoming request.
**Sample Usage**
If the user runs:
.. code-block:: bash
$ curl -H X-My-Header=Bar http://kapow.example:8080/
then, when handling the request:
.. code-block:: bash
$ kapow get /request/headers/X-My-Header
Bar
``/request/cookies/<name>`` Resource
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Contains the value of the HTTP cookie ``name`` of the incoming request.
**Sample Usage**
If the user runs:
.. code-block:: bash
$ curl --cookie "MYCOOKIE=Bar" http://kapow.example:8080/
then, when handling the request:
.. code-block:: bash
$ kapow get /request/cookies/MYCOOKIE
Bar
``/request/form/<name>`` Resource
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Contains the value of the field ``name`` of the incoming request.
**Sample Usage**
If the user runs:
.. code-block:: bash
$ curl -F -d myfield=foo http://kapow.example:8080/
then, when handling the request:
.. code-block:: bash
$ kapow get /request/form/myfield
foo
``/request/files/<name>/filename`` Resource
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Contains the name of the file uploaded through the incoming request.
**Sample Usage**
If the user runs:
.. code-block:: bash
$ curl -F -d myfile=@filename.txt http://kapow.example:8080/
then, when handling the request:
.. code-block:: bash
$ kapow get /request/files/myfile/filename
filename.txt
``/request/files/<name>/content`` Resource
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Contents of the file that is being uploaded in the incoming request.
**Sample Usage**
If the user runs:
.. code-block:: bash
$ curl -F -d myfile=@filename.txt http://kapow.example:8080/
then, when handling the request:
.. code-block:: bash
$ kapow get /request/files/myfile/content
...filename.txt contents...
``/request/body`` Resource
~~~~~~~~~~~~~~~~~~~~~~~~~~
Raw contents of the incoming request HTTP body.
**Sample Usage**
If the user runs:
.. code-block:: bash
$ curl --data-raw foobar http://kapow.example:8080/
then, when handling the request:
.. code-block:: bash
$ kapow get /request/body
foobar
``/response/status`` Resource
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Contains the status code given in the user response.
**Sample Usage**
If during the request handling:
.. code-block:: bash
$ kapow set /response/status 418
then the response will have the status code ``418 I am a Teapot``.
``/response/headers/<name>`` Resource
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Contains the value of the header ``name`` in the user response.
**Sample Usage**
If during the request handling:
.. code-block:: bash
$ kapow set /response/headers/X-My-Header Foo
then the response will contain an HTTP header named ``X-My-Header`` with
value ``Foo``.
``/response/cookies/<name>`` Resource
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Contains the value of the cookie ``name`` that will be set to the user
response.
**Sample Usage**
If during the request handling:
.. code-block:: bash
$ kapow set /response/cookies/MYCOOKIE Foo
then the response will set the cookie ``MYCOOKIE`` to the user in
following requests.
``/response/body`` Resource
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Contains the value of the response HTTP body.
**Sample Usage**
If during the request handling:
.. code-block:: bash
$ kapow set /response/body foobar
then the response will contain ``foobar`` in the body.
+14
View File
@@ -0,0 +1,14 @@
Route Matching
==============
Kapow! maintains a route table with a list of routes as provided by the user,
and uses it to determine which handler should an incoming request be dispatched
to.
.. todo::
link routes to its section
Each incoming request is matched against the routes in the route table in
strict order, for each route in the route table, the criteria are checked.
If the request does not match, the next route in the route list is examined.
+124
View File
@@ -0,0 +1,124 @@
Routes
======
A Kapow! route specifies the matching criteria for an incoming request on
the `User HTTP Interface`, and the details to handle it.
Kapow! implements a *route table* where all routes reside.
A route can be set like this:
.. code-block:: bash
$ kapow route add \
-X POST \
'/register/{username}' \
-e '/bin/bash -c' \
-c 'touch /var/lib/mydb/"$(kapow get /request/matches/username)"' \
| jq
{
"id": "deadbeef-0d09-11ea-b18e-106530610c4d",
"method": "POST",
"url_pattern": "/register/{username}",
"entrypoint": "/bin/bash -c",
"command": "touch /var/lib/mydb/\"$(kapow get /request/matches/username)\""
}
Let's use this example to discuss its elements.
Elements
--------
``id`` Route Element
~~~~~~~~~~~~~~~~~~~~
Uniquely identifies each route. It is used for instance by ``kapow route remove
<route_id>``.
.. note::
The current implementation of Kapow! autogenerates a `UUID` for this field.
In the future the use will be able to specify a custom value.
``method`` Route Element
~~~~~~~~~~~~~~~~~~~~~~~~
Specifies the HTTP method for the route to match the incoming request.
The route shown above will only match a ``POST`` request.
``url_pattern`` Route Element
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
It matches the `path` component of the `URL` of the incoming request.
It can contain regex placeholders for easily capturing fragments of the path.
In the route shown above, a request with a URL ``/register/joe`` would match,
assigning `joe` to the placeholder ``username``.
Kapow! leverages Gorilla Mux for managing routes. For the full story, see
https://github.com/gorilla/mux#examples
``entrypoint`` Route Element
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This sets the executable to be spawned, along with any arguments required.
In the route shown above, the entrypoint that will be run is ``/bin/bash -c``,
which is an incomplete recipe. It is completed by the `command` element.
.. todo::
link to command below
.. note::
The semantics of this element closely match `Docker`'s ``ENTRYPOINT`` directive.
.. todo::
link to Docker docu
``command`` Route Element
~~~~~~~~~~~~~~~~~~~~~~~~~
This is an optional last argument to be passed to the ``entrypoint``.
In the route shown above, it completes the `entrypoint` to form the final
incantation to be executed:
.. todo::
link to entrypoint above
.. code-block::
/bin/bash -c 'touch /var/lib/mydb/"$(kapow get /request/matches/username)"'
.. note::
The semantics of this element closely match `Docker`'s ``COMMAND`` directive.
.. todo::
link to Docker docu
Matching Algorithm
------------------
`Kapow!` leverages Gorilla Mux for this task. You can see the gory details in
their documentation.
.. todo::
link to Gorilla Mux docu