j8a

package module
v1.1.1 Latest Latest
Warning

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

Go to latest
Published: Dec 5, 2023 License: Apache-2.0 Imports: 69 Imported by: 0

README

Circleci Builds Github Workflows Dependabot Github Issues Github Activity
Go Report CodeClimate Maintainability CodeClimate Test Coverage SSLLabs Rating Go Version License Docker Pulls Version

CVEs

🛡️ J8a has zero reported CVEs as of 04/12/2023. If you are a security researcher, the project team would like to hear from you.

What's new?

v1.1.1 (04/12/2023)

  • Update to Go 1.21
  • Fixed a bug where IPV6 addresses as host names weren't logged correctly.
  • Bumped several dependency versions

v1.1.0 (24/06/2023)

  • improved error handling for failed upstream requests.
  • added new internal status management for server bootstrap and shutdown behaviour.
  • bumped several dependencies
  • now validating port ranges for http and tls ports downstream during bootstrap
  • fixed a bug where acceptableSkewSeconds was incorrectly loaded from config files

v1.0.1 (26/05/2023)

  • can now validate config & files with cli option -o
  • added cli flags -h for usage and -v for version

v1.0.0 (07/05/2023)

  • support for virtual host based routing inc subdomains.
  • timeZone and logLevel are now options in config.yml as opposed to env variables.
  • re-introduced support for HTTP PATCH method.
  • OPTIONS requests to '*' now list legal server HTTP methods
  • update to go 1.20, and multiple dependency updates

What is j8a?

j8a [ dʒʌbbʌ ] is a modern TLS 1.3 reverse proxy server designed as a lightweight API gateway for REST APIs.

Features

  • Fast! 5k POST req/s traffic.
  • Secure. TLS1.2, TLS/1.3 termination w/ A+ SSLLabs rating.
  • Zero downtime. Auto-renew certs using ACME RFC 8555.
  • Observable. API request tracing w/ correlation ID for upstream microservices.
  • APM. CPU, memory logging built-in. Daily TLS health and validity check for your full certificate chain.
  • JWT token validation with full JWK(S) support for RFC 7519.
  • HTTP/1.1 and HTTP/2 support w/ upstream <> downstream protocol translation.
  • Websocket Support for RFC 6455
  • Docker native

Up and running

Docker

docker pull simonmittag/j8a &&
  docker run -e J8ACFG_YML -p443:443 simonmittag/j8a

Homebrew

brew tap simonmittag/cli && 
  brew install j8a && 
  j8a

Golang

go install github.com/simonmittag/j8a/cmd/j8a &&
  j8a

Usage

J8a runs from the cli. The process will attempt to load its configuration from the environment variable J8ACFG_YML, a specified config file, or the default config file j8acfg.yml (in that order). You can validate the config using the -o flag without actually starting the server, which is useful for ci/cd pipelines. In validate mode, the process successfully exits with 0, or -1 in case of failure.

Commandline Options

λ j8a -h
j8a[v1.0.1] Goodde da lodia!
Usage: j8a [-c] [-o] | [-v] | [-h]
  -c string
        config file location (default "j8acfg.yml").
  -h    print usage instructions.
  -o    validate config file, then exit.
  -v    print version.

Examples

Validate Server Configuration supplied as myconfig.yml

λ j8a -c myconfig.yml -o
6:25PM INF hostName determined hostName=MacBook-Pro-16.local
6:25PM INF version determined version=v1.0.1
6:25PM INF srvID determined srvID=c91cda8c
...

Start Server With Configuration supplied as myconfig.yml

λ j8a -c myconfig.yml 
6:25PM INF hostName determined hostName=MacBook-Pro-16.local
6:25PM INF version determined version=v1.0.1
6:25PM INF srvID determined srvID=c91cda8c
...

Start Server With Configuration supplied via J8ACFG_YML

J8ACFG_YML="---
            connection:
              downstream:
                http:
                  port: 80
            routes:
              - path: "/todos"
                resource: jsonplaceholder
            resources:
              jsonplaceholder:
                - url:
                    scheme: https
                    host: jsonplaceholder.typicode.com
                    port: 443" j8a

Contributions

The j8a team is looking for and welcomes all contributors. Everyone interacting with the project's codebase, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct

Release Cycle

  • Now that 1.0 is reached, we usually release 3/4 minor versions per year.
  • Bug-fixes (e.g. 1.0.1, 1.0.2) are released as needed (no additional features are delivered in those versions, bug-fixes only).
  • Each version is supported until the next one is released (e.g. 1.1.x will be supported until 1.2.0 is out).

We use Semantic Versioning.

Documentation

Index

Constants

View Source
const AcceptEncodingS = "Accept-Encoding"
View Source
const COMMA = ","
View Source
const Days30 = time.Duration(time.Hour * 24 * 30)
View Source
const Days398 = PDuration(time.Hour * 24 * 398)
View Source
const DefaultConfigFile = "j8acfg.yml"
View Source
const EOF = "EOF"
View Source
const HTTP = "HTTP"
View Source
const HTTP11 = "1.1"
View Source
const HTTPS = "https://"
View Source
const J8ACFG_YML = "J8ACFG_YML"
View Source
const Q = "?"
View Source
const STAR = "*"
View Source
const Server string = "Server"

Version is the server version

View Source
const TLS = "TLS"
View Source
const UpgradeHeader = "Upgrade"
View Source
const XRequestID = "X-Request-Id"

XRequestID is a per HTTP request unique identifier

Variables

View Source
var ConfigFile = ""
View Source
var GzipContentEncodings = AcceptEncoding{EncGzip, EncXGzip}
View Source
var ID string = "unknown"

ID is a unique server ID

View Source
var SupportedContentEncodings = AcceptEncoding{EncStar, EncIdentity, EncBrotli, EncGzip, EncXGzip}
View Source
var Version string = "v1.1.1"

Functions

func BootStrap

func BootStrap()

BootStrap starts up the server from a ServerConfig

func BrotliDecode added in v0.9.1

func BrotliDecode(input []byte) *[]byte

BrotliDecode decodes a []byte from Brotli binary format

func BrotliEncode added in v0.9.1

func BrotliEncode(input []byte) *[]byte

BrotliEncode encodes to brotli from byte array.

func ChunkString added in v0.9.0

func ChunkString(s string, chunkSize int) []string

func Gunzip

func Gunzip(input []byte) *[]byte

Gunzip a []byte

func Gzip

func Gzip(input []byte) *[]byte

Gzip a []byte

func JoinHashString added in v0.9.0

func JoinHashString(hash []byte) string

func RandomHuttese added in v1.0.1

func RandomHuttese() string

func ShutDown added in v1.1.0

func ShutDown()

func Validate added in v1.0.1

func Validate()

Types

type AboutResponse

type AboutResponse struct {
	J8a      string
	ServerID string
	Version  string
}

AboutResponse exposes standard environment

func (AboutResponse) AsJSON

func (aboutResponse AboutResponse) AsJSON() []byte

AsJSON renders the status Code response into a JSON string as []byte

func (AboutResponse) AsString

func (aboutResponse AboutResponse) AsString() string

type AcceptEncoding added in v0.9.1

type AcceptEncoding []ContentEncoding

func (AcceptEncoding) Print added in v0.9.1

func (ae AcceptEncoding) Print() string

type Acme added in v0.9.0

type Acme struct {
	// Acme Provider, currently supports letsencrypt
	Provider string

	// Domain
	Domains []string

	// Email for registration.
	Email string

	// Number of days before certificate expiry that triggers first renewal attempt
	GracePeriodDays int
}

type AcmeHandler added in v0.9.0

type AcmeHandler struct {
	Active   map[string]bool
	Domains  map[string]string
	KeyAuths map[string][]byte
}

func NewAcmeHandler added in v0.9.0

func NewAcmeHandler() *AcmeHandler

func (*AcmeHandler) CleanUp added in v0.9.0

func (a *AcmeHandler) CleanUp(domain, token, keyAuth string) error

func (*AcmeHandler) Present added in v0.9.0

func (a *AcmeHandler) Present(domain, token, keyAuth string) error

type AcmeUser added in v0.9.0

type AcmeUser struct {
	Email        string
	Registration *registration.Resource
	// contains filtered or unexported fields
}

func (*AcmeUser) GetEmail added in v0.9.0

func (u *AcmeUser) GetEmail() string

func (*AcmeUser) GetPrivateKey added in v0.9.0

func (u *AcmeUser) GetPrivateKey() crypto.PrivateKey

func (AcmeUser) GetRegistration added in v0.9.0

func (u AcmeUser) GetRegistration() *registration.Resource

type Atmpt

type Atmpt struct {
	URL             *URL
	Label           string
	Count           int
	StatusCode      int
	ContentEncoding ContentEncoding

	CompleteHeader chan struct{}
	CompleteBody   chan struct{}
	Aborted        <-chan struct{}
	AbortedFlag    bool
	CancelFunc     func()
	// contains filtered or unexported fields
}

Atmpt wraps connection attempts to specific upstreams that are already mapped by label

type Config

type Config struct {
	Policies            map[string]Policy
	Routes              Routes
	Jwt                 map[string]*Jwt
	Resources           map[string][]ResourceMapping
	Connection          Connection
	DisableXRequestInfo bool
	TimeZone            string
	LogLevel            string
}

Config is the system wide configuration for j8a

type Connection

type Connection struct {
	Downstream Downstream
	Upstream   Upstream
}

Connection Params

type ConnectionWatcher added in v0.9.3

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

func (*ConnectionWatcher) AddDwn added in v0.9.3

func (cw *ConnectionWatcher) AddDwn(c int64)

Add adds c to the number of active connections.

func (*ConnectionWatcher) AddUp added in v0.9.3

func (cw *ConnectionWatcher) AddUp(c int64)

func (*ConnectionWatcher) DwnCount added in v0.9.3

func (cw *ConnectionWatcher) DwnCount() uint64

Count returns the number of connections at the time the call.

func (*ConnectionWatcher) DwnMaxCount added in v0.9.3

func (cw *ConnectionWatcher) DwnMaxCount() uint64

func (*ConnectionWatcher) OnStateChange added in v0.9.3

func (cw *ConnectionWatcher) OnStateChange(conn net.Conn, state http.ConnState)

OnStateChange records open connections in response to connection state changes. Set net/http Server.ConnState to this method as value.

func (*ConnectionWatcher) SetUp added in v0.9.3

func (cw *ConnectionWatcher) SetUp(c uint64)

func (*ConnectionWatcher) UpCount added in v0.9.3

func (cw *ConnectionWatcher) UpCount() uint64

func (*ConnectionWatcher) UpMaxCount added in v0.9.3

func (cw *ConnectionWatcher) UpMaxCount() uint64

func (*ConnectionWatcher) UpdateMaxDwn added in v0.9.3

func (cw *ConnectionWatcher) UpdateMaxDwn(c uint64)

Sets the maximum number of active connections observed

func (*ConnectionWatcher) UpdateMaxUp added in v0.9.3

func (cw *ConnectionWatcher) UpdateMaxUp(c uint64)

type ContentEncoding added in v0.9.1

type ContentEncoding string
const (
	EncStar      ContentEncoding = "*"
	EncIdentity  ContentEncoding = "identity"
	EncBrotli    ContentEncoding = "br"
	EncGzip      ContentEncoding = "gzip"
	EncXGzip     ContentEncoding = "x-gzip"
	EncDeflate   ContentEncoding = "deflate"
	EncXDeflate  ContentEncoding = "x-deflate"
	EncCompress  ContentEncoding = "compress"
	EncXCompress ContentEncoding = "x-compress"
)

func NewContentEncoding added in v0.9.1

func NewContentEncoding(raw string) ContentEncoding

type DNSNameComponents added in v1.0.0

type DNSNameComponents WeightedSlugs

func NewDNSNameComponents added in v1.0.0

func NewDNSNameComponents(r Route) DNSNameComponents

type Down

type Down struct {
	Req            *http.Request
	Resp           Resp
	Method         string
	Host           string
	Path           string
	URI            string
	UserAgent      string
	AcceptEncoding AcceptEncoding
	Body           []byte
	Aborted        <-chan struct{}
	AbortedFlag    bool
	Timeout        <-chan struct{}
	TimeoutFlag    bool
	ReqTooLarge    bool

	HttpVer  string
	TlsVer   string
	Port     int
	Listener string
	// contains filtered or unexported fields
}

Down wraps downstream exchange

type Downstream

type Downstream struct {
	// ReadTimeoutSeconds is the maximum duration for reading the entire
	// request, including the body, the downstream user agent sends to us.
	ReadTimeoutSeconds int

	// WriteTimeoutSeconds is the maximum duration round trip time in seconds any
	// single request spends in the server, this includes the time to read the request,
	// processing upstream attempts and writing the response into downstream socket.
	RoundTripTimeoutSeconds int

	// IdleTimeoutSeconds is the maximum duration, a downstream idle socket connection is kept open
	// before the server hangs up on the downstream user agent.
	IdleTimeoutSeconds int

	// MaxBodyBytes is the maximum size of the incoming HTTP request body before it is rejected
	MaxBodyBytes int64

	// Http block. defaults to on
	Http Http

	// Tls block defaults to off
	Tls Tls
}

Downstream params for the HTTP or TLS server that j8a exposes

type HTTPClient

type HTTPClient interface {
	Do(req *http.Request) (*http.Response, error)
	Get(uri string) (*http.Response, error)
}

type HandlerDelegate added in v0.8.0

type HandlerDelegate struct{}

func (HandlerDelegate) ServeHTTP added in v0.8.0

func (hd HandlerDelegate) ServeHTTP(w http.ResponseWriter, r *http.Request)

type Http added in v0.7.5

type Http struct {
	// Serving HTTP on this port
	Port int

	// Redirect HTTP to tls if set to "TLS". Only one value allowed.
	Redirecttls bool
}

type Jwt added in v0.7.0

type Jwt struct {
	Name string
	Alg  string
	// Jwt key supports pem encoding for public keys, certificates unencoded secrets for hmac.
	Key string
	// JwksUrl loads remotely.
	JwksUrl               string
	RSAPublic             KeySet
	ECDSAPublic           KeySet
	Secret                KeySet
	AcceptableSkewSeconds string
	Claims                []string
	// contains filtered or unexported fields
}

func NewJwt added in v0.7.1

func NewJwt(name string, alg string, key string, jwksUrl string, acceptableSkewSeconds string, claims ...string) *Jwt

func (*Jwt) Init added in v0.7.1

func (jwt *Jwt) Init()

we need this separate because the JSON unmarshaller creates this object without asking us.

func (*Jwt) LoadJwks added in v0.7.0

func (jwt *Jwt) LoadJwks() error

TODO this method needs a refactor and has high cognitive complexity

func (*Jwt) UnmarshalJSON added in v1.1.0

func (j *Jwt) UnmarshalJSON(data []byte) error

func (*Jwt) Validate added in v0.7.1

func (jwt *Jwt) Validate() error

type KeySet added in v0.7.0

type KeySet []KidPair

func (*KeySet) Find added in v0.7.1

func (ks *KeySet) Find(kid string) interface{}

func (*KeySet) Upsert added in v0.7.1

func (ks *KeySet) Upsert(kp KidPair)

type KidPair added in v0.7.0

type KidPair struct {
	Kid string
	Key interface{}
}

type LabelWeight

type LabelWeight struct {
	Label  string
	Weight float64
}

LabelWeight describes routing to labels

type PDuration

type PDuration time.Duration

func (PDuration) AsDays

func (p PDuration) AsDays() int

func (PDuration) AsDuration

func (p PDuration) AsDuration() time.Duration

func (PDuration) AsString

func (p PDuration) AsString() string

type Policy

type Policy []LabelWeight

Policy defines an array of LabelWeights used for routing

func (Policy) Len

func (policy Policy) Len() int

func (Policy) Less

func (policy Policy) Less(i, j int) bool

func (Policy) Swap

func (policy Policy) Swap(i, j int)

type Proxy

type Proxy struct {
	XRequestID   string
	XRequestInfo bool
	Up           Up
	Dwn          Down
	Route        *Route
}

Proxy wraps data for a single downstream request/response with multiple upstream HTTP request/response cycles.

type ReloadableCert added in v0.9.0

type ReloadableCert struct {
	Cert *tls.Certificate

	Init bool
	// contains filtered or unexported fields
}

func (*ReloadableCert) GetCertificateFunc added in v0.9.0

func (r *ReloadableCert) GetCertificateFunc(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error)

type ResourceMapping

type ResourceMapping struct {
	Name   string
	Labels []string
	URL    URL
}

ResourceMapping describes upstream servers

type Resp

type Resp struct {
	Writer          http.ResponseWriter
	StatusCode      int
	Message         string
	Body            *[]byte
	ContentLength   int64
	ContentEncoding ContentEncoding
}

Resp wraps downstream http response writer and data

type Route

type Route struct {
	Host              string         //idna host pattern
	PunyHost          string         //punycode host pattern
	CompiledPunyHost  *regexp.Regexp // as regex
	Path              string
	PathType          string // exact | prefix
	CompiledPathRegex *regexp.Regexp
	Transform         string
	Resource          string
	Policy            string
	Jwt               string
}

Route maps a Path to an upstream resource

type RoutePath added in v1.0.0

type RoutePath WeightedSlugs

func NewRoutePath added in v1.0.0

func NewRoutePath(r Route) RoutePath

type RoutePathTypes added in v1.0.0

type RoutePathTypes []string

func NewRoutePathTypes added in v1.0.0

func NewRoutePathTypes() RoutePathTypes

type Routes

type Routes []Route

func (Routes) HostIsLess added in v1.0.0

func (s Routes) HostIsLess(i int, j int) bool

func (Routes) Len

func (s Routes) Len() int

func (Routes) Less

func (s Routes) Less(i, j int) bool

func (Routes) PathIsLess added in v1.0.0

func (s Routes) PathIsLess(i int, j int) bool

func (Routes) Swap

func (s Routes) Swap(i, j int)

type Runtime

type Runtime struct {
	Config
	Start          time.Time
	StateHandler   *StateHandler
	Memory         []sample
	AcmeHandler    *AcmeHandler
	ReloadableCert *ReloadableCert

	ConnectionWatcher ConnectionWatcher
	// contains filtered or unexported fields
}

Runtime struct defines runtime environment wrapper for a config.

var Runner *Runtime

Runner is the Live environment of the server

func (*Runtime) CountUpConns added in v0.9.3

func (rt *Runtime) CountUpConns(proc *process.Process, cs procspy.ConnIter, ips map[string][]net.IP) int

func (*Runtime) FindUpConns added in v0.9.3

func (rt *Runtime) FindUpConns() (procspy.ConnIter, error)

func (*Runtime) LookUpResourceIps added in v0.9.3

func (rt *Runtime) LookUpResourceIps() map[string][]net.IP

type State added in v1.1.0

type State string
const (
	Bootstrap State = "Bootstrap"
	Daemon    State = "Daemon"
	Shutdown  State = "Shutdown"
)

func (State) Lesser added in v1.1.0

func (s State) Lesser(t State) bool

type StateHandler added in v1.1.0

type StateHandler struct {
	Current State
	Update  chan State
}

func NewStateHandler added in v1.1.0

func NewStateHandler() *StateHandler

type StatusCodeResponse

type StatusCodeResponse struct {
	AboutResponse
	Code    int
	Message string
}

StatusCodeResponse defines a JSON structure for a canned HTTP response

func (StatusCodeResponse) AsJSON

func (statusCodeResponse StatusCodeResponse) AsJSON() []byte

AsJSON renders the status Code response into a JSON string as []byte

func (StatusCodeResponse) AsString

func (statusCodeResponse StatusCodeResponse) AsString() string

type TLSType

type TLSType string
const (
	TLS12         TLSType = "1.2"
	TLS13         TLSType = "1.3"
	TLS_UNKNOWN   TLSType = "unknown"
	TLS_NONE      TLSType = "none"
	Authorization         = "Authorization"
	Sep                   = " "
)

type Tls added in v0.7.5

type Tls struct {
	// Serving on this port
	Port int

	// TLS x509 certificate
	Cert string

	// TLS secret key
	Key string

	// Acme config for TLS. Optional, but conflicts with Cert and Key
	Acme Acme
}
type TlsLink struct {
	// contains filtered or unexported fields
}

type URL

type URL struct {
	Scheme string
	Host   string
	Port   string
}

URL describes host mapping

func (URL) String

func (u URL) String() string

String representation of our URL struct

func (*URL) UnmarshalJSON added in v1.1.0

func (u *URL) UnmarshalJSON(data []byte) error

type Up

type Up struct {
	Atmpt  *Atmpt
	Atmpts []Atmpt
	Count  int
}

Up wraps upstream

type Upstream

type Upstream struct {

	// PoolSize is the maximum size of the client socket connection pool for idle connections
	PoolSize int

	// IdleTimeoutSeconds is the total wait period in seconds before we hang up on an idle upstream connection.
	IdleTimeoutSeconds int

	// SocketTimeoutSeconds is the wait period to establish socket connection with an upstream server.
	// This setting controls roundtrip time for establishing simple TCP connections, combined with handshake time for TLS
	// if applicable.
	SocketTimeoutSeconds int

	// ReadTimeoutSeconds is the wait period to read the entire upstream response once connection was established
	// before an individual upstream request is aborted
	ReadTimeoutSeconds int

	// MaxAttempts is the maximum allowable number of request attempts to obtain a successful response for repeatable
	// HTTP requests.
	MaxAttempts int

	// TlsInsecureSkipVerify skips the host name validation and certificate chain verification of upstream connections
	// using TLS. Use this only for testing or if you know what you are doing. Defaults to false
	TlsInsecureSkipVerify bool
}

Upstream connection params for remote servers that are being proxied

type WebsocketStatus added in v0.8.0

type WebsocketStatus struct {
	DwnOpCode ws.OpCode
	DwnExit   error
	UpOpCode  ws.OpCode
	UpExit    error
}

type WebsocketTx added in v0.8.0

type WebsocketTx struct {
	UpBytesRead   int64
	UpBytesWrite  int64
	DwnBytesRead  int64
	DwnBytesWrite int64
}

type WeightedSlugs added in v1.0.0

type WeightedSlugs []string

func (WeightedSlugs) Less added in v1.0.0

func (w WeightedSlugs) Less(w2 WeightedSlugs) bool

Directories

Path Synopsis
cmd
j8a

Jump to

Keyboard shortcuts

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