My frontend proxy for Kubernetes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Patrick Spek 893a8945a6
Add charset and proxy headers
5 months ago
bin Bump version to 0.2.0 5 months ago
lib/Kubernetes/FrontendProxy Add charset and proxy headers 5 months ago
resources Convert 4-space indents to tabs 6 months ago
t Add support for suppressing security headers 5 months ago
.editorconfig Initial commit 6 months ago
.gitignore Initial commit 6 months ago
.gitlab-ci.yml Initial commit 6 months ago
CHANGELOG.md Add charset and proxy headers 5 months ago
Dockerfile Add support for suppressing security headers 5 months ago
META6.json Bump version to 0.2.0 5 months ago
README.pod6 Add charset and proxy headers 5 months ago

README.pod6

=begin pod

=NAME Kubernetes::FrontendProxy
=AUTHOR Patrick Spek <p.spek@tyil.work>
=VERSION 0.2.0

=head1 Description

A frontend proxy server for use with L<Kubernetes|https://kubernetes.io/>, using
L<Perl 6|https://perl6.org> for configuration and automatisation,
L<Nginx|https://nginx.org> for the webserver and
L<Certbot|https://certbot.eff.org/> for dealing with TLS certificates.

=head1 Installation

This module is intended to be run as a Kubernetes pod, but should be usable as a
natively-ran program as well. It is available as a Docker image under the name
C<tyil/frontend-proxy>, which can be used in a Kubernetes deployment. It will
need a service to be exposed to the outside world.

It is also recommended to add 2 PersistentVolumes. One for endpoint
configuration, and one for the LetsEncrypt certificates. These should be mounted
on C</etc/feproxy/hosts> and C</etc/letsencrypt> respectively.

=head2 Kubernetes deployment

This deployment is I<just> the bare basics to get the frontend proxy to run. You
will need to add endpoint configurations for it to generate usable Nginx
configurations.

=begin code
---
apiVersion: v1
kind: Service
metadata:
name: frontend
spec:
type: ClusterIP
selector:
intent: frontend
ports:
- name: http
protocol: TCP
port: 80
targetPort: 80
- name: https
protocol: TCP
port: 443
targetPort: 443
externalIPs:
- 127.0.0.1

---
apiVersion: apps/v1
kind: Deployment
metadata:
name: feproxy
spec:
replicas: 1
selector:
matchLabels:
intent: feproxy
template:
metadata:
labels:
app: feproxy
intent: frontend
spec:
containers:
- name: feproxy
image: tyil/frontend-proxy:latest
env:
- name: FEPROXY_LE_EMAIL
value: lets-encrypt@tyil.net
ports:
- containerPort: 80
- containerPort: 443
=end code

=head1 Configuration

Some aspects of the application are configured through environment variables.
Other than that, you will need a Persistent Volume containing configurations for
all the endpoints you wish to expose through the frontend proxy.

=head2 Environment variables

=head3 FEPROXY_HOSTS

The C<FEPROXY_HOSTS> variable indicates the directory that will contain the
configuration for the hosts and their endpoints. It defaults to
C</etc/feproxy/hosts>.

=head3 FEPROXY_LE_EMAIL

B<Required>. This is the email address to use when requesting new certificates
through C<certbot>.

=head3 FEPROXY_LE_RENEW_INTERVAL

This is the interval in which C<certbot> is instructed to renew the
certificates, in seconds. This defaults to C<21600>, which is 6 hours.

=head2 Endpoint configurations

The endpoints are configured using L<TOML|https://github.com/toml-lang/toml>
files in the directory specified by C<$FEPROXY_HOSTS>. The recommended layout is
a directory per hostname, and a file per endpoint.

=begin code
/etc/feproxy/hosts
├── www.tyil.nl
│ ├── api.toml
│ └── www.toml
└── tyil.nl
└── main.toml
=end code

The structure laid out above is not enforced. I<All> files in the hosts
directory (and any directory below it) are attempted to be parsed as TOML files
containing possible endpoint configurations. Any files that fail to parse or
validate will generate a warning.

Each TOML file requires an C<[endpoint]> section, and an additional section
depending on the type of endpoint. The C<[endpoint]> section must have the
C<host>, C<path> and C<type> keys:

=begin code
[endpoint]
host = "www.tyil.nl"
path = "/"
type = "service"
=end code

=head3 Headers

This block is completely optional, but can be used to adjust the headers sent by
nginx. These headers are used to enhance security on the endpoints you expose,
and are used only by I<Services>. If you find that an application you're
running requires some of these headers to be turned off, you can specify those
in this section. All the headers default to C<true>.

=begin code
[headers]
csp = true
rp = true
uir = true
xcto = true
xfo = true
xxp = true
xpcdp = true
=end code

Z<Change this into =defn blocks, once they're supported>
=item1 C<csp> Content-Security-Policy
=item1 C<rp> Referrer-Policy
=item1 C<uir> Upgrade-Insecure-Requests
=item1 C<xcto> X-Content-Type-Options
=item1 C<xfo> X-Frame-Options
=item1 C<xxp> X-XSS-Protection
=item1 C<xpcdp> X-Permitted-Cross-Domain-Policies

=head3 Service

A service type requires a C<[service]> section, which must have a C<name> key.
Optionally, they can also use keys for C<protocol> and C<port>. The C<protocol>
is C<http> by default. The C<port> is C<80> by default.

=begin code
[service]
name = "tyil-blog"
=end code

=head4 name

B<Required>. The name of the Kubernetes service you want to create an endpoint
for.

=head4 protocol

The protocol to use to access the service. This defaults to C<http>.

=head4 port

The port to use to access the service. This defaults to C<80>.

=head4 charset

The character set to use for the content served on this endpoint. This defaults
to C<utf-8>.

=head3 Redirect

A redirect type requires a C<[redirect]> section, which can have the following
keys:

=begin code
[redirect]
host = "www.tyil.nl"
=end code

=head4 host

B<Required>. The name of the host to redirect to.

=head4 status

The HTTP status code to use for the redirect. This defaults to C<301>.

=head4 protocol

The protocol to redirect to. This defaults to C<https>.

=head4 path

The path to add to the URI to redirect to. It defaults to the Nginx value of
C<$request_uri>, which is the part after the first C</>. This makes it so the
redirect points to the same location as was requested, but with a different
hostname.

=head1 License

This module is distributed under the terms of the AGPL-3.0.

=end pod