websocket_proxy

package module
v0.0.0-...-c2e68b0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 16, 2021 License: GPL-3.0 Imports: 13 Imported by: 0

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.

Documentation

Index

Constants

View Source
const (
	AuthParam  = "param"
	AuthHeader = "header"
)
View Source
const (
	KeyManagerEnv            = "env"
	KeyManagerFile           = "file"
	KeyManagerSecretsManager = "aws_sm"
)
View Source
const Timeout = time.Hour * 24 * 7

Variables

This section is empty.

Functions

This section is empty.

Types

type Auth

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

Auth is the generic interface for how the client passes in their API key for authentication

func NewAuth

func NewAuth(authType string) Auth

NewAuth returns a pointer of an Auth implementation based on the type that was passed in

type Env

type Env struct {
	// contains filtered or unexported fields
}

Env takes a comma separated env var and uses the content as keys

func (*Env) FetchKeys

func (e *Env) FetchKeys() error

FetchKeys sets the keys from the env var

func (*Env) ValidateKey

func (e *Env) ValidateKey(key string) bool

ValidateKey returns a boolean to whether a key given is present

type File

type File struct {
	// contains filtered or unexported fields
}

File manages keys on the local disk

func (*File) FetchKeys

func (f *File) FetchKeys() error

FetchKeys sets the keys from the file on local disk

func (*File) ValidateKey

func (f *File) ValidateKey(key string) bool

ValidateKey returns a boolean to whether a key given is present in the file

type Header struct{}

Header is the Auth implementation that requires `X-API-KEY` to be set in the request headers

func (*Header) Authenticate

func (p *Header) Authenticate(r *http.Request, km KeyManager) bool

Authenticate takes the `X-API-KEY` in the request headers and then authenticates it with the KeyManager

type KeyManager

type KeyManager interface {
	ValidateKey(string) bool
	FetchKeys() error
	// contains filtered or unexported methods
}

KeyManager is a generic interface for implementing a specific backend for managing API keys

func NewKeyManager

func NewKeyManager(keyManagerType string, id string) KeyManager

NewKeyManager returns a pointer of an KeyManager implementation based on the type of KeyManager that was provided

type Keys

type Keys []string

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

type Param

type Param struct{}

Param is the Auth implementation that requires `apikey` in GET parameters to be set with the key

func (*Param) Authenticate

func (p *Param) Authenticate(r *http.Request, km KeyManager) bool

Authenticate takes the `apikey` in the GET param and then authenticates it with the KeyManager

type SecretsManager

type SecretsManager struct {
	// contains filtered or unexported fields
}

SecretsManager is the KeyManager implementation for AWS Secrets Manager

func (*SecretsManager) FetchKeys

func (sm *SecretsManager) FetchKeys() error

FetchKeys sets the keys from the manager backend into memory for use on client auth

func (*SecretsManager) ValidateKey

func (sm *SecretsManager) ValidateKey(key string) bool

ValidateKey returns a boolean to whether a key given is present in the manager

type WebsocketProxy

type WebsocketProxy interface {
	Dial() (*websocket.Conn, error)
	Handler(w http.ResponseWriter, r *http.Request)
	Close()
	Wait(<-chan os.Signal)
}

WebsocketProxy is the generic interface for a proxy implementation

func NewProxy

func NewProxy(
	url *url.URL,
	header http.Header,
	origins []string,
	auth Auth,
	keyManager KeyManager,
) (WebsocketProxy, error)

NewProxy returns a configured WebsocketProxy instance and fetches keys if required

func NewSimpleProxy

func NewSimpleProxy(url *url.URL) (WebsocketProxy, error)

NewSimpleProxy returns a configured proxy instance from just a url

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL