Categorygithub.com/jleeh/websocket-proxy
modulepackage
0.0.0-20211116145822-37406c6ed56c
Repository: https://github.com/jleeh/websocket-proxy.git
Documentation: pkg.go.dev

# README

WebSocket Proxy

Lightweight WebSocket proxy with API key management built on top of gorilla/websockets. This can either be imported for use in your own implementations with the http.Handler interface, or installed directly to be used as a CLI.

Supported authentication methods:

  • Headers (X-API-KEY)
  • GET Param (apikey)

Supported key management tools:

  • Local file
  • AWS Secrets Manager

Install & Build

go get -d github.com/jleeh/websocket-proxy && go build -o $GOPATH/bin/websocket-proxy

Running the Proxy

Docker

docker run -e SERVER=ws://localhost:3000 -it jonnyh/websocket-proxy:latest

Local

You can run the WebSocket proxy by just running the built binary:

./websocket-proxy

Configure

Configuration for the CLI is via Viper, so configuration variables can be passed in via environment variables or file.

Example configuration:

port: 8080
server: ws://localhost:3000
auth_type: header
key_manager_type: file
key_identifier: /home/me/keys.json
allowed_origins:
  - localhost
  - google.com

Example .env file:

PORT=80
SERVER=ws://localhost:3000
AUTH_TYPE=header
KEY_MANAGER_TYPE=file
KEY_IDENTIFIER=/home/me/keys.json
ALLOWED_ORIGINS=localhost,google.com

Using AWS Secrets Manager

Change the key_manager_type configuration variable to aws_sm and then change the key_identifier to the name of the secret in AWS.

Custom Example

go get github.com/jleeh/websocket-proxy/proxy
package main

import (
	"github.com/jleeh/websocket-proxy/proxy"
	"log"
	"net/http"
	"net/url"
)

func main() {
	u, _ := url.Parse("ws://localhost:3000")
	wp, _ := proxy.NewSimpleProxy(u)
	
	http.HandleFunc("/", wp.Handler)
	log.Fatal(http.ListenAndServe(":80", nil))
}

Extending Authentication

Interface:

type Auth interface {
	Authenticate(*http.Request, KeyManager) bool
}

Implementation example (header):

// Header is the Auth implementation that requires `X-API-KEY` to be set
// in the request headers
type Header struct{}

// Authenticate takes the `X-API-KEY` in the request headers and then authenticates
// it with the KeyManager
func (p *Header) Authenticate(r *http.Request, km KeyManager) bool {
	key := r.Header.Get("X-API-KEY")
	return km.ValidateKey(key)
}

You can create your own implementation of an Auth type to then pass into the proxy.NewProxy(...) method.

Extending KeyManager

Interface:

type KeyManager interface {
	ValidateKey(string) bool
	FetchKeys() error
	setIdentifier(string)
}

Implementation example (file):

// File manages keys on the local disk
type File struct {
	id string
	keys []string
}

// ValidateKey returns a boolean to whether a key given is present in the file
func (f *File) ValidateKey(key string) bool {
	for _, k := range f.keys {
		if k == key {
			return true
		}
	}
	return false
}

// FetchKeys sets the keys from the file on local disk
func (f *File) FetchKeys() error {
	if file, err := os.Open(f.id); err != nil {
		return err
	} else if b, err := ioutil.ReadAll(file); err != nil {
		return err
	} else if err := json.Unmarshal(b, &f.keys); err != nil {
		return err
	}
	return nil
}

func (f *File) setIdentifier(id string) {
	f.id = id
}

You can create your own implementation of a KeyManager type to then pass into the proxy.NewProxy(...) method.

# Packages

No description provided by the author

# Functions

NewAuth returns a pointer of an Auth implementation based on the type that was passed in.
NewKeyManager returns a pointer of an KeyManager implementation based on the type of KeyManager that was provided.
NewProxy returns a configured WebsocketProxy instance and fetches keys if required.
NewSimpleProxy returns a configured proxy instance from just a url.

# Constants

No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author

# Structs

Env takes a comma separated env var and uses the content as keys.
File manages keys on the local disk.
Header is the Auth implementation that requires `X-API-KEY` to be set in the request headers.
Param is the Auth implementation that requires `apikey` in GET parameters to be set with the key.
SecretsManager is the KeyManager implementation for AWS Secrets Manager.

# Interfaces

Auth is the generic interface for how the client passes in their API key for authentication.
KeyManager is a generic interface for implementing a specific backend for managing API keys.
WebsocketProxy is the generic interface for a proxy implementation.

# Type aliases

Keys type is the representation of how keys are stored in the manager.