sohop

package module
v0.9.1 Latest Latest
Warning

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

Go to latest
Published: Mar 14, 2017 License: ISC Imports: 28 Imported by: 0

README

sohop

GoDoc build status report card

This program is a reverse proxy that can optionally restrict access to users authenticated with OAuth (currently supports authorizing members of a specified Github organization, or users whose Google account email matches a specified regex). It also provides a health check endpoint that reports the reachability of the upstream services.

I use it to expose erstwhile intranet apps to the public internet while continuing to restrict access, and without having to configure authentication / authorization in the intranet apps themselves. They are installed as if they're still behind a firewall, and sohop handles auth / auth. This is a configuration that is tilted very much towards the usability end of the usability / security spectrum and may not be appropriate for your use case.

Assumptions

  • All outgoing traffic uses HTTPS (HTTP requests are redirected to the HTTPS equivalent URL)
  • Each upstream is accessed on a subdomain of the same domain (no path rewriting)
  • Upstreams are only accessed via a trusted network. WARNING Since many services in my use case use self-signed certs, SSL verification is disabled when communicating with proxied services.
  • Subdomains health and oauth are reserved
    • health.<domain>/check provides a health check endpoint for all proxied services.
    • oauth.<domain>/authorize is used as the oauth callback.
    • oauth.<domain>/session shows the user the values in their session.

Features

  • Simple authentication with OAuth
  • Automatic TLS certificates via Let's Encrypt
  • Proxies WebSocket connections
  • HTTP/2 support when compiled with Go >= 1.6
  • Replace headers that are forwarded using session cookies and Go templates
  • Simple, forkable codebase (maybe not yet but I'd like to get there). Configure your web server in Go!

Installation

go get github.com/davars/sohop/cmd/sohop

Usage

Usage of sohop:
  -config string
    	Config file (default "config.json")
  -httpAddr string
    	Address to bind HTTP server (default ":80")
  -httpsAddr string
    	Address to bind HTTPS server (default ":443")

Example Configs

{
  "Domain": "example.com",
  "Cookie": {
    "Name": "exampleauth",
    "Secret": "27e21c8d866594bd446c4a509d890ce2f59dcb26d89751b77ca236e5be3e0d7c26532a60e1ed9fd4f7b924e363d64e7a44a56dd57d84cf34eb7f0db0e19889f5"
  },  
  "Auth" : {
    "Type": "github-org",
    "Config": {
	  "ClientID": "12345678",
	  "ClientSecret": "12345678",
	  "OrgID": 12345678
	}
  },
  "TLS": {
    "CertFile": "cert.pem",
    "CertKey": "key.pem"
  },
  "Upstreams": {
    "intranet": {
      "URL": "http://10.0.0.16:8888",
      "HealthCheck": "http://10.0.0.16:8888/login",
      "WebSocket": "ws://10.0.0.16:8888",
      "Auth": true,
      "Headers": { "X-WEBAUTH-USER":["{{.Session.Values.user}}"] }
    },
    "public": {
      "URL": "http://10.0.0.16:8111",
      "HealthCheck": "http://10.0.0.16:8111/login.html",
      "WebSocket": "ws://10.0.0.16:8111",
      "Auth": false
    }
  }
}
{
  "Domain": "example.com",    
  "Auth" : {
    "Type": "gmail-regex",
    "Config": {
	  "Credentials": {"web":{"client_id":"XXXX-yyyyyy.apps.googleusercontent.com","project_id":"example","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://accounts.google.com/o/oauth2/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_secret":"zzzzZZzzZZ","redirect_uris":["https://oauth.example.com/authorized"]}},
	  "EmailRegex":"^davars@gmail.com$"
	}
  },
  "Upstreams": {

...

  }
}

The config file id unmarshalled into a sohop.Config struct, described here: https://godoc.org/github.com/davars/sohop#Config

Testing

go test ./...

Roadmap

  • Docs
  • Tests
  • Google Auth (email regex)
  • Let's Encrypt provision / renewal
  • Google Auth (Apps domain) (needs advocate)
  • Google Auth (groups) (needs advocate)

Rant

There seems to be a trend where all config file formats trend towards Turing-completeness over time. Life is too short for understanding the directives of yet another arbitrary config file format, and still not being free from having to patch the software anyway when it falls just short of your needs. I'd rather have all of Go available to me when 'configuring' my web server so that I can perform truly arbitrary processing on requests.

Contributing

Contributions welcome! Please fork the repository and open a pull request with your changes.

License

This is free software, licensed under the ISC license.

Documentation

Overview

Package sohop implements an OAuth-authenticating reverse proxy.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Config

type Config struct {
	// Domain is the domain to which the subdomains belong. Also used as the
	// domain for the session cookie.
	Domain string

	// Upstreams is an array of configurations for upstream servers.  Keys are
	// the subdomain to proxy to the configured server.  Values describe
	// various aspects of the upstream server.
	Upstreams map[string]UpstreamConfig

	// Auth configures the auth middleware.
	Auth auth.Config

	// Cookie configures the session cookie store.
	Cookie CookieConfig

	// TLS can be used to specify a static TLS configuration for the server.
	// It is overridden by the values from the AcmeWrapper if Acme is used.
	TLS TLSConfig

	// Acme configures automatic provisioning and renewal of TLS certificates
	// using the ACME protocol.
	Acme *acme.Config

	// Deprecated.  See https://godoc.org/github.com/davars/sohop/auth#Config.
	Github *auth.GithubAuth

	// Deprecated.  See https://godoc.org/github.com/davars/sohop/auth#Config.
	Google *auth.GoogleAuth
}

A Config can be used to set up a sohop proxy

type CookieConfig

type CookieConfig struct {
	// Name is the name of the session cookie.  If not set, a random name will
	// be generated on start-up.
	Name string

	// Secret is the private key used to authenticate session cookies. Should be
	// a hex-encoded string 128 characters in length (64 byte key).  If not set,
	// a random key will be generated on start-up.  Run `openssl rand -hex 64`
	// to generate a key.
	Secret string
}

CookieConfig configures the session cookie store.

type Server

type Server struct {
	Config    *Config
	HTTPAddr  string
	HTTPSAddr string
	// contains filtered or unexported fields
}

A Server is an OAuth-authenticating reverse proxy.

func (Server) HealthHandler

func (s Server) HealthHandler() http.Handler

HealthHandler checks each upstream and considers them healthy if they return a 200 response. Also, the health check will fail if the TLS certificate will expire within 72 hours.

func (Server) ProxyHandler

func (s Server) ProxyHandler() http.Handler

ProxyHandler selects the appropriate upstream based on subdomain of the incoming request and does the proxying.

func (Server) Run

func (s Server) Run()

Run bootstraps the listeners then waits forever.

type TLSConfig

type TLSConfig struct {
	// CertFile is a path to the PEM-encoded server certificate.
	CertFile string

	// CertKey is a path to the unencrypted PEM-encoded private key for the
	// server certificate.
	CertKey string
}

TLSConfig configures the server certificate.

type UpstreamConfig

type UpstreamConfig struct {
	// The URL of the upstream server.
	URL string

	// Auth is whether requests to this upstream require authentication.
	Auth bool

	// HealthCheck is a URL to use as a health check, if different from
	// Upstreams.URL (for example if UpstreamConfig.URL returns a 302 response).
	// It should return a 200 response if the upstream is healthy.
	HealthCheck string

	// WebSocket is a ws:// or wss:// URL receive proxied WebSocket connections.
	WebSocket string

	// Headers can be used to replace the headers of an incomping request
	// before it is sent upstream.  The values are templates, evaluated with the
	// current session available as `.Session`.
	Headers http.Header
}

UpstreamConfig configures a single upstream endpoint.

Directories

Path Synopsis
Package acme uses https://github.com/dkumor/acmewrapper to automatically provision TLS certificates.
Package acme uses https://github.com/dkumor/acmewrapper to automatically provision TLS certificates.
Package auth implements the OAuth authentication flows for sohop.
Package auth implements the OAuth authentication flows for sohop.
cmd
sohop
Package main implements the CLI for sohop.
Package main implements the CLI for sohop.
Package store provices an implementation of sessions.Store that also carries its name around with it.
Package store provices an implementation of sessions.Store that also carries its name around with it.

Jump to

Keyboard shortcuts

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