Skip to content

Latest commit

 

History

History
118 lines (83 loc) · 3.92 KB

README.md

File metadata and controls

118 lines (83 loc) · 3.92 KB

amproxy - Authenticated Metrics Proxy

Go Reference Go Report Card

A proxy for Graphite's Carbon service that authenticates messages before passing them on to Carbon or dropping them on the floor.

What does this do?

Carbon listens on port 2003 and doesn't offer any sort of authentication. Usually this is manageable by firewalling off the service to only allow connections from hosts you trust. The problem is that I want to build a device that my friends/family run on their networks at home (without static IPs) and report metrics to my Carbon server. I could run some sort of dynamic dns client on each device and dynamically manage my firewall, but I don't really want to deal with that or with doing something like mTLS, or using something like MQTT.

Instead, I run Carbon bound to 127.0.0.1:2003 and run amproxy on port 2005 exposed to the internet. The client devices are each given a public/private key pair that can be used to generate signed messages. These signed messages are sent to amproxy which authenticates the message by validating the signature and whether or not the specified metric is authorized for the given key pair, and if so, forwards the metric on to Carbon.

Configuration

$ amproxy server --help
Starts the server

Usage:
  amproxy server [flags]

Flags:
      --addr string          The interface and port to bind the server to. Can be set with the ADDR env variable (default "127.0.0.1:2005")
      --auth-file string     The path to the auth file. Can be set with the AUTH_FILE env variable (default "/etc/amproxy/auth_file.yaml")
      --carbon-addr string   The address of the carbon server. Can be set with the CARBON_ADDR env variable (default "127.0.0.1:2003")
  -h, --help                 help for server
      --log-format string    The format of log messages. (logfmt|json) (default "logfmt")
      --log-level string     Log level (all|err|warn|info|debug (default "info")
      --skew duration        The amount of clock skew tolerated. Can be set with the MAX_SKEW env variable (default 5m0s)

Auth File Format

---
apikeys:
  my_public_key:
    secret_key: my_secret_key
    metrics:
    - metric1
    - metric2
  my_public_key2:
    secret_key: my_secret_key2
    metrics:
    - metric3
    - metric4

In the example above, my_public_key is authorized for metric1 and metric2 and uses the my_secret_key private key.

If the AUTH_FILE is updated on disk, it will automatically get reloaded within 60 seconds.

Protocol

Messages going over the wire are in the form:

metric value timestamp public_key base64_signature

Example

metric = foo
value = 1234
timestamp = 1425059762
public_key = my_public_key
secret_key = my_secret_key

The message for which we will generate the signature becomes

foo 1234 1425059762 my_public_key

We can generate a signature:

KEY_PRIVATE=my_secret_key amproxy client signature "foo 1234 1425059762 my_public_key"

Which outputs the following:

lT9zOeBVNfTdogqKE5J7p3XWprfu/gOI5D7aWRzjJtc=

The message going over the wire becomes:

foo 1234 1425059762 my_public_key lT9zOeBVNfTdogqKE5J7p3XWprfu/gOI5D7aWRzjJtc=

Testing

To start a graphite/carbon stack, run:

docker-compose up

Then access the graphite webui at localhost:8080. Username and password are both root.

Start the server in another terminal:

AUTH_FILE=packaging/redhat/auth_file.yaml go run main.go server

Start the test client in another terminal:

KEY_PUBLIC=my_public_key KEY_PRIVATE=my_secret_key go run main.go client test-client

The test-client will send a metric named metric1 every 60 seconds with a random value between 30 and 100.