Documentation
¶
Overview ¶
Package caddydicer routes Caddy's reverse proxy to Dicer instances chosen by their labels: an ingress for the virtual machines a Dicer daemon runs.
It adds two modules. http.reverse_proxy.upstreams.dicer is a dynamic upstream source. A route names a label selector and a port, and its requests go to that port on every instance whose labels match:
app.example.com {
reverse_proxy {
dynamic dicer app=web 8080
}
}
Alternatively, instances can carry their routing in the caddy.host and caddy.port labels. A route with no selector then sends each request to the instances that serve its host:
:80 {
reverse_proxy {
dynamic dicer
}
}
The second module, tls.permission.dicer, allows on-demand TLS certificates only for the hosts those labels list.
Build Caddy with the plugin using xcaddy:
xcaddy build --with github.com/kazysgurskas/caddy-dicer
See Upstreams for what is routed to, PermissionByLabel for certificates, and the selector package for the syntax of a selector.
Index ¶
- type Daemon
- type PermissionByLabel
- func (PermissionByLabel) CaddyModule() caddy.ModuleInfo
- func (p *PermissionByLabel) CertificateAllowed(_ context.Context, name string) error
- func (p *PermissionByLabel) Cleanup() error
- func (p *PermissionByLabel) Provision(ctx caddy.Context) error
- func (p *PermissionByLabel) UnmarshalCaddyfile(d *caddyfile.Dispenser) error
- func (p *PermissionByLabel) Validate() error
- type TLSConfig
- type Upstreams
- func (Upstreams) CaddyModule() caddy.ModuleInfo
- func (u *Upstreams) Cleanup() error
- func (u *Upstreams) GetUpstreams(r *http.Request) ([]*reverseproxy.Upstream, error)
- func (u *Upstreams) Provision(ctx caddy.Context) error
- func (u *Upstreams) UnmarshalCaddyfile(d *caddyfile.Dispenser) error
- func (u *Upstreams) Validate() error
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Daemon ¶
type Daemon struct {
// The daemon's address, as a gRPC target: unix:///path/to/socket, or
// host:port for its TCP listener. Default: the local daemon's socket,
// unix:///run/dicer/dicer.sock. Placeholders are replaced, as in token.
Address string `json:"address,omitempty"`
// The token for the daemon's TCP listener, which requires one. The
// socket needs none. Placeholders are replaced, so that the token can
// be kept out of the configuration: {env.DICER_TOKEN}, or
// {file./etc/caddy/dicer-token}. Surrounding whitespace, such as a
// file's last newline, is dropped.
Token string `json:"token,omitempty"`
// How to verify a daemon whose certificate a certificate authority
// signed. A daemon's self-signed certificate needs none of this: the
// token carries its fingerprint.
TLS *TLSConfig `json:"tls,omitempty"`
// The host at which Caddy reaches the ports that instances publish on
// every address. Default: the host in address, for a TCP listener at
// an address that is not loopback, or otherwise the gateway address of
// the instance's network. Set it when address reaches the daemon through a
// proxy on another machine, or by a name that resolves to a loopback
// address. Placeholders are replaced, as in token.
PublishedPortHost string `json:"published_port_host,omitempty"`
}
Daemon identifies the Dicer daemon a module follows and how to reach it. Upstreams and PermissionByLabel embed it.
type PermissionByLabel ¶
type PermissionByLabel struct {
Daemon
// contains filtered or unexported fields
}
PermissionByLabel is a permission module for on-demand TLS. It allows a certificate only for a host listed in a Dicer instance's caddy.host label, whatever state the instance is in, so a site that routes by those labels does not need to name its hosts:
{
on_demand_tls {
permission dicer
}
}
https:// {
tls {
on_demand
}
reverse_proxy {
dynamic dicer
}
}
It follows the daemon as Upstreams does, and shares the connection with every Upstreams that names the same daemon.
func (PermissionByLabel) CaddyModule ¶
func (PermissionByLabel) CaddyModule() caddy.ModuleInfo
CaddyModule returns the Caddy module information.
func (*PermissionByLabel) CertificateAllowed ¶
func (p *PermissionByLabel) CertificateAllowed(_ context.Context, name string) error
CertificateAllowed returns nil if an instance's caddy.host label lists name, and an error wrapping caddytls.ErrPermissionDenied otherwise.
func (*PermissionByLabel) Cleanup ¶
func (p *PermissionByLabel) Cleanup() error
Cleanup releases the connection to the daemon, which closes once no configuration uses it.
func (*PermissionByLabel) Provision ¶
func (p *PermissionByLabel) Provision(ctx caddy.Context) error
Provision connects to the daemon, unless another module already has, and waits briefly for its instances to be listed.
func (*PermissionByLabel) UnmarshalCaddyfile ¶
func (p *PermissionByLabel) UnmarshalCaddyfile(d *caddyfile.Dispenser) error
UnmarshalCaddyfile sets up the module from Caddyfile tokens:
permission dicer {
address <target>
token <token>
published_port_host <host>
tls {
ca <file>
server_name <name>
}
}
func (*PermissionByLabel) Validate ¶
func (p *PermissionByLabel) Validate() error
Validate checks the configuration.
type TLSConfig ¶
type TLSConfig struct {
// The PEM file of the certificate authority that signed the daemon's
// certificate. Default: the system's trusted authorities. It is read
// each time the configuration is loaded, so a reload picks up a change.
CA string `json:"ca,omitempty"`
// The name the daemon's certificate must carry. Default: the host in
// the daemon's address.
ServerName string `json:"server_name,omitempty"`
}
TLSConfig is how to verify a daemon whose certificate a certificate authority signed. A daemon's self-signed certificate needs none of it: the token carries its fingerprint.
type Upstreams ¶
type Upstreams struct {
Daemon
// Which instances to route to, as a label selector such as
// "app=web,tier in (frontend,edge)". Without one, a request goes to the
// instances whose caddy.host label lists its host.
Selector string `json:"selector,omitempty"`
// The guest port the instances serve on. An instance's caddy.port label
// overrides it. Without either, requests go to the only port an
// instance publishes, and an instance that publishes none, or several,
// gets none.
Port int `json:"port,omitempty"`
// contains filtered or unexported fields
}
Upstreams routes to Dicer instances chosen by their labels. It is a dynamic upstream source for reverse_proxy.
A route chooses its instances with a selector, such as "app=web". Instances can also declare which requests they serve, so the Caddyfile does not have to. An instance labelled caddy.host=shop.example.com only gets requests for that host, and on a route with no selector it gets every request for it. Its caddy.port label overrides the route's port.
If an instance publishes its guest port on the host, requests go to the published port. If neither the route nor the instance's labels name a port, they go to the only port the instance publishes. A connection to a published port wakes an instance on standby. An instance that publishes no port gets requests at its own address on its network, which Caddy must be able to reach: run it on the daemon's host.
It routes to instances that are running, have an address, and, if they have a health check, have been found healthy. When a route has no such instance, it routes to one instance with standby_after instead. It prefers one whose health check has no verdict yet, such as one just woken. Otherwise it picks the first instance on standby, in name order, that publishes the port its requests go to. A route whose instances have all gone on standby therefore wakes one at a time.
It only needs to list instances and networks, and to follow instance events. Over the daemon's TCP listener, give it a token with just those scopes:
dicer token create caddy --scopes instances:read,events:read,networks:read
It lists networks only to learn their gateway addresses, where it reaches ports published on every address when the listener is on a loopback address. A token for a listener on any other address does not need networks:read.
The instances are kept up to date from the daemon's events, so a request never waits on the daemon. While the daemon cannot be reached, the instances it last reported are routed to.
func (Upstreams) CaddyModule ¶
func (Upstreams) CaddyModule() caddy.ModuleInfo
CaddyModule returns the Caddy module information.
func (*Upstreams) Cleanup ¶
Cleanup releases the connection to the daemon, which closes once no configuration uses it.
func (*Upstreams) GetUpstreams ¶
GetUpstreams returns an upstream for each routable instance that serves r, in name order. If there is none, it returns one for the route's fallback instance, if any. It returns no upstreams, and no error, when no instance serves r.
func (*Upstreams) Provision ¶
Provision connects to the daemon, unless another module already has, and waits briefly for its instances to be listed.
func (*Upstreams) UnmarshalCaddyfile ¶
UnmarshalCaddyfile sets up the module from Caddyfile tokens:
dynamic dicer [<selector> [<port>]] {
address <target>
token <token>
selector <selector>
port <port>
published_port_host <host>
tls {
ca <file>
server_name <name>
}
}
A selector with spaces, such as one with "in (a, b)", is quoted. With no selector, requests are routed by the instances' caddy.host labels.