config

package
v0.0.96 Latest Latest
Warning

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

Go to latest
Published: May 3, 2024 License: MIT Imports: 24 Imported by: 0

Documentation

Overview

Package config provides various parameters(configuration optionals) that can be used to configure ong.

Index

Examples

Constants

View Source
const (
	// DefaultLoadShedSamplingPeriod is the duration over which we calculate response latencies by default.
	DefaultLoadShedSamplingPeriod = 12 * time.Minute
	// DefaultLoadShedMinSampleSize is the minimum number of past requests that have to be available, in the last `loadShedSamplingPeriod` for us to make a decision, by default.
	// If there were fewer requests(than `loadShedMinSampleSize`) in the `loadShedSamplingPeriod`, then we do decide to let things continue without load shedding.
	DefaultLoadShedMinSampleSize = 50
	// DefaultLoadShedBreachLatency is the p99 latency at which point we start dropping requests, by default.
	//
	// The value chosen here is because;
	// The wikipedia [monitoring] dashboards are public.
	// In there we can see that the p95 [response] times for http GET requests is ~700ms, & the p95 response times for http POST requests is ~900ms.
	// Thus, we'll use a `loadShedBreachLatency` of ~700ms. We hope we can do better than wikipedia(chuckle emoji.)
	//
	// [monitoring]: https://grafana.wikimedia.org/?orgId=1
	// [response]: https://grafana.wikimedia.org/d/RIA1lzDZk/application-servers-red?orgId=1
	DefaultLoadShedBreachLatency = 700 * time.Millisecond
)

loadshed middleware.

View Source
const (
	// DirectIpStrategy derives the client IP from [http.Request.RemoteAddr].
	// It should be used if the server accepts direct connections, rather than through a proxy.
	DirectIpStrategy = clientip.DirectIpStrategy

	// LeftIpStrategy derives the client IP from the leftmost valid & non-private IP address in the `X-Fowarded-For` or `Forwarded` header.
	LeftIpStrategy = clientip.LeftIpStrategy

	// RightIpStrategy derives the client IP from the rightmost valid & non-private IP address in the `X-Fowarded-For` or `Forwarded` header.
	RightIpStrategy = clientip.RightIpStrategy

	// ProxyStrategy derives the client IP from the [PROXY protocol v1].
	// This should be used when your application is behind a TCP proxy that uses the v1 PROXY protocol.
	//
	// [PROXY protocol v1]: https://www.haproxy.org/download/2.8/doc/proxy-protocol.txt
	ProxyStrategy = clientip.ProxyStrategy
)

clientip middleware.

View Source
const (
	// DefaultMaxBodyBytes is the value used as the limit for incoming request bodies, if a custom value was not provided.
	//
	// [Nginx] uses a default value of 1MB, [Apache] uses default of 1GB whereas [Haproxy] does not have such a limit.
	//
	// The max size for http [forms] in Go is 10MB. The max size of the entire bible in text form is ~5MB.
	// Thus here, we are going to use the 2 times the default size for forms.
	// Note that; from the [code] and [docs], it looks like; if you set the maxBodyBytes, this also becomes the maxFormSize.
	//
	// [Nginx]: http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size
	// [Apache]: https://httpd.apache.org/docs/2.4/mod/core.html#limitrequestbody
	// [Haproxy]: https://discourse.haproxy.org/t/how-can-you-configure-the-nginx-client-max-body-size-equivalent-in-haproxy/1690/2
	// [forms]: https://github.com/golang/go/blob/go1.20.3/src/net/http/request.go#L1233-L1235
	// [code]: https://github.com/golang/go/blob/go1.20.3/src/net/http/request.go#L1233-L1235
	// [code]: https://pkg.go.dev/net/http#Request.ParseForm
	DefaultMaxBodyBytes = uint64(2 * 10 * 1024 * 1024) // 20MB

	// DefaultServerLogLevel is the log level of the logger that will be passed into [http.Server.ErrorLog], if no custom value is provided.
	DefaultServerLogLevel = slog.LevelInfo

	// DefaultDrainDuration is used to determine the shutdown duration if a custom one is not provided.
	DefaultDrainDuration = 13 * time.Second

	// LetsEncryptProductionUrl is the URL of [letsencrypt's] certificate authority directory endpoint for production.
	LetsEncryptProductionUrl = "https://acme-v02.api.letsencrypt.org/directory"
	// LetsEncryptStagingUrl is the URL of [letsencrypt's] certificate authority directory endpoint for staging.
	LetsEncryptStagingUrl = "https://acme-staging-v02.api.letsencrypt.org/directory"
)
View Source
const (
	// DefaultCorsCacheDuration is the length in time that preflight responses will be cached by default.
	// 2hrs is chosen since that is the maximum for chromium based browsers.
	// Firefox had a maximum of 24hrs as at the time of writing.
	DefaultCorsCacheDuration = 2 * time.Hour
)

cors middleware.

View Source
const (
	// DefaultCsrfCookieDuration is the duration that csrf cookie will be valid for by default.
	//
	// At the time of writing; gorilla/csrf uses 12hrs, django uses 1yr & gofiber/fiber uses 1hr.
	DefaultCsrfCookieDuration = 12 * time.Hour
)

csrf

View Source
const (
	// DefaultRateLimit is the maximum requests allowed (from one IP address) per second, by default.
	//
	// The figure chosen here is because;
	// [github] uses a rate limit of 1 reqs/sec (5_000 reqs/hr).
	// [twitter] uses 1 reqs/sec (900 reqs/15mins).
	// [stripe] uses 100 reqs/sec.
	//
	// [github]: https://docs.github.com/en/developers/apps/building-github-apps/rate-limits-for-github-apps
	// [twitter]: https://developer.twitter.com/en/docs/twitter-api/rate-limits
	// [stripe]: https://stripe.com/docs/rate-limits
	DefaultRateLimit = 100.00
)

ratelimit middleware.

View Source
const (
	// DefaultRateShedSamplePercent is the percentage of rate limited or loadshed responses that will be logged as errors, by default.
	DefaultRateShedSamplePercent = 10
)

logging middleware.

View Source
const (
	// DefaultSessionCookieDuration is the duration that session cookie will be valid for by default.
	// [django] uses a value of 2 weeks by default.
	//
	// [django]: https://docs.djangoproject.com/en/4.1/ref/settings/#session-cookie-age
	DefaultSessionCookieDuration = 14 * time.Hour
)

session middleware.

Variables

This section is empty.

Functions

func DefaultSessionAntiReplyFunc added in v0.0.83

func DefaultSessionAntiReplyFunc(r *http.Request) string

DefaultSessionAntiReplyFunc is the function used, by default, to try and mitigate against replay attacks. It is a no-op.

Types

type ClientIPstrategy

type ClientIPstrategy = clientip.ClientIPstrategy

ClientIPstrategy is a middleware option that describes the strategy to use when fetching the client's IP address.

Warning: This should be used with caution. Clients CAN easily spoof IP addresses. Fetching the "real" client is done in a best-effort basis and can be grossly inaccurate & precarious. You should especially heed this warning if you intend to use the IP addresses for security related activities. Proceed at your own risk.

func SingleIpStrategy added in v0.0.82

func SingleIpStrategy(headerName string) ClientIPstrategy

SingleIpStrategy derives the client IP from http header headerName.

headerName MUST NOT be either `X-Forwarded-For` or `Forwarded`. It can be something like `CF-Connecting-IP`, `Fastly-Client-IP`, `Fly-Client-IP`, etc; depending on your usecase.

type Opts

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

Opts are the various parameters(optionals) that can be used to configure ong.

Use either New, WithOpts, DevOpts, CertOpts, AcmeOpts or LetsEncryptOpts to get a valid Opts.

func AcmeOpts

func AcmeOpts(

	domain string,
	secretKey string,
	strategy ClientIPstrategy,
	logger *slog.Logger,

	acmeEmail string,
	tlsHosts []string,
	acmeDirectoryUrl string,
) Opts

AcmeOpts returns a new Opts that procures certificates from an ACME certificate authority. It panics on error. Also see LetsEncryptOpts

See New for extra documentation.

func CertOpts

func CertOpts(

	domain string,
	secretKey string,
	strategy ClientIPstrategy,
	logger *slog.Logger,

	certFile string,
	keyFile string,
	tlsHosts []string,
) Opts

CertOpts returns a new Opts that has sensible defaults given certFile & keyFile. It panics on error.

See New for extra documentation.

func DevOpts

func DevOpts(logger *slog.Logger, secretKey string) Opts

DevOpts returns a new Opts that has sensible defaults, especially for dev environments. It also automatically creates & configures the developer TLS certificates/key. It panics on error.

See New for extra documentation.

func LetsEncryptOpts

func LetsEncryptOpts(

	domain string,
	secretKey string,
	strategy ClientIPstrategy,
	logger *slog.Logger,

	acmeEmail string,
	tlsHosts []string,
) Opts

LetsEncryptOpts returns a new Opts that procures certificates from letsencrypt. It panics on error. Also see AcmeOpts

See New for extra documentation.

func New

func New(

	domain string,
	port uint16,

	secretKey string,
	strategy ClientIPstrategy,
	logger *slog.Logger,
	rateShedSamplePercent int,
	rateLimit float64,
	loadShedSamplingPeriod time.Duration,
	loadShedMinSampleSize int,
	loadShedBreachLatency time.Duration,
	allowedOrigins []string,
	allowedMethods []string,
	allowedHeaders []string,
	allowCredentials bool,
	corsCacheDuration time.Duration,
	csrfTokenDuration time.Duration,
	sessionCookieDuration time.Duration,
	sessionAntiReplyFunc func(r *http.Request) string,

	maxBodyBytes uint64,
	serverLogLevel slog.Level,
	readHeaderTimeout time.Duration,
	readTimeout time.Duration,
	writeTimeout time.Duration,
	idleTimeout time.Duration,
	drainTimeout time.Duration,
	certFile string,
	keyFile string,
	acmeEmail string,
	tlsHosts []string,
	acmeDirectoryUrl string,
	clientCertificatePool *x509.CertPool,
) Opts

New returns a new Opts. It panics on error.

domain is the domain name of your website. It can be an exact domain, subdomain or wildcard. port is the TLS port where the server will listen on. Http requests will also redirected to that port.

secretKey is used for securing signed data. It should be unique & kept secret. If it becomes compromised, generate a new one and restart your application using the new one.

strategy is the algorithm to use when fetching the client's IP address; see ClientIPstrategy. It is important to choose your strategy carefully, see the warning in ClientIPstrategy.

logger is an slog.Logger that will be used for logging.

rateShedSamplePercent is the percentage of rate limited or loadshed responses that will be logged as errors. If it is less than 0, DefaultRateShedSamplePercent is used instead.

rateLimit is the maximum requests allowed (from one IP address) per second. If it is les than 1.0, DefaultRateLimit is used instead.

loadShedSamplingPeriod is the duration over which we calculate response latencies for purposes of determining whether to loadshed. If it is less than 1second, DefaultLoadShedSamplingPeriod is used instead. loadShedMinSampleSize is the minimum number of past requests that have to be available, in the last [loadShedSamplingPeriod] for us to make a decision, by default. If there were fewer requests(than [loadShedMinSampleSize]) in the [loadShedSamplingPeriod], then we do decide to let things continue without load shedding. If it is less than 1, DefaultLoadShedMinSampleSize is used instead. loadShedBreachLatency is the p99 latency at which point we start dropping(loadshedding) requests. If it is less than 1nanosecond, DefaultLoadShedBreachLatency is used instead.

allowedOrigins, allowedMethods, allowedHeaders, allowCredentials & corsCacheDuration are used by the CORS middleware. If allowedOrigins is nil, all origins are allowed. You can also use []string{"*"} to allow all. If allowedMethods is nil, "GET", "POST", "HEAD" are allowed. Use []string{"*"} to allow all. If allowedHeaders is nil, "Origin", "Accept", "Content-Type", "X-Requested-With" are allowed. Use []string{"*"} to allow all. allowCredentials indicates whether the request can include user credentials like cookies, HTTP authentication or client side SSL certificates. corsCacheDuration is the duration that preflight responses will be cached. If it is less than 1second, DefaultCorsCacheDuration is used instead.

csrfTokenDuration is the duration that csrf cookie will be valid for. If it is less than 1second, DefaultCsrfCookieDuration is used instead.

sessionCookieDuration is the duration that session cookie will be valid. If it is less than 1second, DefaultSessionCookieDuration is used instead. sessionAntiReplyFunc is the function used to return a token that will be used to try and mitigate against replay attacks. This mitigation not foolproof. If it is nil, DefaultSessionAntiReplyFunc is used instead.

maxBodyBytes is the maximum size in bytes for incoming request bodies. If this is zero, a reasonable default is used.

serverLogLevel is the log level of the logger that will be passed into http.Server.ErrorLog

readHeaderTimeout is the amount of time a server will be allowed to read request headers. readTimeout is the maximum duration a server will use for reading the entire request, including the body. writeTimeout is the maximum duration before a server times out writes of the response. idleTimeout is the maximum amount of time to wait for the next request when keep-alives are enabled. drainTimeout is the duration to wait for after receiving a shutdown signal and actually starting to shutdown the server. This is important especially in applications running in places like kubernetes.

certFile is a path to a tls certificate. keyFile is a path to a tls key.

acmeEmail is the e-address that will be used if/when procuring certificates from an ACME certificate authority, eg letsencrypt. tlsHosts is the list of hosts for which we are allowed to fetch TLS certificates for. Wildcards are also accepted. If tlsHosts is nil, [domain] is used instead. acmeDirectoryUrl is the URL of the ACME certificate authority's directory endpoint.

If certFile is a non-empty string, this will enable tls using certificates found on disk. If acmeEmail is a non-empty string, this will enable tls using certificates procured from an ACME certificate authority.

clientCertificatePool is an x509.CertPool, that will be used to verify client certificates. Use this option if you would like to perform mutual TLS authentication. The given pool will be used as is, without modification.

Example
package main

import (
	"context"
	"fmt"
	"log/slog"
	"net/http"
	"os"
	"time"

	"github.com/komuw/ong/config"
	"github.com/komuw/ong/log"
	"github.com/komuw/ong/middleware"
)

func loginHandler() http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		_, _ = fmt.Fprint(w, "welcome to your favorite website.")
	}
}

func main() {
	l := log.New(context.Background(), os.Stdout, 100)
	opts := config.New(
		// The domain where our application will be available on.
		"example.com",
		// The https port that our application will be listening on.
		443,
		// The security key to use for securing signed data.
		"super-h@rd-Pas1word",
		// In this case, the actual client IP address is fetched from the given http header.
		config.SingleIpStrategy("CF-Connecting-IP"),
		// Logger.
		l,
		// log 90% of all responses that are either rate-limited or loadshed.
		90,
		// If a particular IP address sends more than 13 requests per second, throttle requests from that IP.
		13.0,
		// Sample response latencies over a 5 minute window to determine if to loadshed.
		5*time.Minute,
		// If the number of responses in the last 5minutes is less than 10, do not make a loadshed determination.
		10,
		// If the p99 response latencies, over the last 5minutes is more than 200ms, then start loadshedding.
		200*time.Millisecond,
		// Allow access from these origins for CORs.
		[]string{"example.net", "example.org"},
		// Allow only GET and POST for CORs.
		[]string{"GET", "POST"},
		// Allow all http headers for CORs.
		[]string{"*"},
		// Do not allow requests to include user credentials like cookies, HTTP authentication or client side SSL certificates
		false,
		// Cache CORs preflight requests for 1day.
		24*time.Hour,
		// Expire csrf cookie after 3days.
		3*24*time.Hour,
		// Expire session cookie after 6hours.
		6*time.Hour,
		// Use a given header to try and mitigate against replay-attacks.
		func(r *http.Request) string { return r.Header.Get("Anti-Replay") },
		//
		// The maximum size in bytes for incoming request bodies.
		2*1024*1024,
		// Log level of the logger that will be passed into [http.Server.ErrorLog]
		slog.LevelError,
		// Read header, Read, Write, Idle timeouts respectively.
		1*time.Second,
		2*time.Second,
		4*time.Second,
		4*time.Minute,
		// The duration to wait for after receiving a shutdown signal and actually starting to shutdown the server.
		17*time.Second,
		// Tls certificate and key. This are set to empty string since we wont be using them.
		"",
		"",
		// Email address to use when procuring TLS certificates from an ACME authority.
		"my-acme@example.com",
		// The hosts that we will allow to fetch certificates for.
		[]string{"api.example.com", "example.com"},
		// The ACME certificate authority to use.
		"https://acme-staging-v02.api.letsencrypt.org/directory",
		// [x509.CertPool], that will be used to verify client certificates
		nil,
	)
	handler := middleware.Get(loginHandler(), opts)
	_ = handler // use handler

}
Output:

func WithOpts

func WithOpts(

	domain string,
	httpsPort uint16,
	secretKey string,
	strategy ClientIPstrategy,
	logger *slog.Logger,

) Opts

WithOpts returns a new Opts that has sensible defaults. It panics on error.

See New for extra documentation.

func (Opts) Equal

func (o Opts) Equal(other Opts) bool

Equal compares two Opts for equality. It was added for testing purposes.

func (Opts) GoString

func (o Opts) GoString() string

GoString implements fmt.GoStringer

func (Opts) String

func (o Opts) String() string

String implements fmt.Stringer

Jump to

Keyboard shortcuts

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