dotege

module
v1.3.1 Latest Latest
Warning

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

Go to latest
Published: Mar 25, 2022 License: MIT

README

== Dotege

Dotege is a tool to automatically generate configuration files from templates
based on running docker containers. It also obtains SSL certificates for
domains using Let's Encrypt, and can send a signal (such as HUP) to another
container when the template changes.

Out of the box it supports writing a HAProxy configuration file with
appropriate entries for all containers with `com.chameth.*` labels.
This enables automatic reverse proxying to any container with the
relevant networks.

=== Configuration

Dotege is configured using environment variables:

==== Certificates

`DOTEGE_CERTIFICATE_DEPLOYMENT`::
Determines how Dotege will deploy certificates. Valid options are:
+
* `disabled`: Dotege will not request certificates or deploy them to disk.
* `combined`: The certificate and private key will be written to one `.pem` file. Default.
* `splitkeys`: The certificate will be written to a `.pem` file, and the private key to a `.key` file.

+
If certificate deployment is disabled, no other options in this section are used.

`DOTEGE_CERT_DESTINATION`::
The folder where certificates will be placed. Defaults to `/data/certs`.

`DOTEGE_CERT_GID`::
If specified, certificate files will be `chowned` to this numeric group ID.

`DOTEGE_CERT_MODE`::
The file mode that should be applied to certificate files. Defaults to `0600`.
+
Take care when configuring this in a YAML file as YAML supports octal integers, resulting in the wrong value being
passed:
+
[source,yaml]
----
DOTEGE_CERT_MODE: 0640   # Passes a mode string of "416" to Dotege due to octal->decimal conversion
DOTEGE_CERT_MODE: 640    # Works as expected
DOTEGE_CERT_MODE: "0640" # Works as expected
----

`DOTEGE_CERT_UID`::
If specified, certificate files will be `chowned` to this numeric user ID.

`DOTEGE_DNS_PROVIDER`::
The DNS provider to use. Must be one https://go-acme.github.io/lego/dns/[supported by Lego].
The DNS provider will also be configured using environmental variables, as documented by
the Lego project. Required if certificate deployment is enabled.

`DOTEGE_ACME_CACHE_FILE`::
The path to a JSON file to store ACME credentials and certificates. This file will
contain the private keys for all certificates generated by Dotege, so must not
be accessible to other users or processes. Defaults to `/data/config/certs.json`.

`DOTEGE_ACME_EMAIL`::
The e-mail address to provide to the ACME service for updates, renewal reminders, etc.
Required if certificate deployment is enabled.

`DOTEGE_ACME_ENDPOINT`::
The ACME server to request certificates from. Defaults to the Let's Encrypt production
server at https://acme-v02.api.letsencrypt.org/directory. For staging, this can be set
to https://acme-staging-v02.api.letsencrypt.org/directory.

`DOTEGE_ACME_KEY_TYPE`::
The key type to use for private keys when generating a certificate using ACME. Valid
values are:
+
  * `P256` for EC256
  * `P384` for EC384
  * `2048` for RSA-2048
  * `4096` for RSA-4096
  * `8192` for RSA-8192
+
The default value is `P384`.

`DOTEGE_WILDCARD_DOMAINS`::
A space or comma separated list of domains that should use wildcard certificates.
Defaults to an empty list.

==== Other settings

`DOTEGE_DEBUG`::
Enables advanced logging of certain information in Dotege. Comma-separated list of
topics to enable logging for. Optional. Valid options are:
+
* `containers` - containers that are seen to start/stop
* `headers` - custom headers (`com.chameth.headers` labels)
* `hostnames` - mapping of containers to hostnames

`DOTEGE_PROXYTAG`::
Only containers with a matching `com.chameth.proxytag` label will be processed by
Dotege. This allows you to run multiple instances that handle separate containers.
If not specified, any container without a `com.chameth.proxytag` label will be
included.

`DOTEGE_SIGNAL_CONTAINER`::
The name of a container that should be sent a signal when the template or certificates
are changed. No signal is sent if not specified.

`DOTEGE_SIGNAL_TYPE`::
The type of signal to send to the `DOTEGE_SIGNAL_CONTAINER`. Defaults to `HUP`.

`DOTEGE_TEMPLATE_DESTINATION`::
Location to write the templated configuration file to. Defaults to `/data/output/haproxy.cfg`.

`DOTEGE_TEMPLATE_SOURCE`::
Path to a template to use to generate configuration. Defaults to `./templates/haproxy.cfg.tpl`,
which is a bundled basic template for generating HAProxy configurations.

`DOTEGE_USERS`::
A YAML (or JSON) list of users, their password hashes, and their group memberships, to use for
ACLs. See <<acls,Using ACLs>> below for detailed usage.

=== Docker labels

Dotege operates by parsing labels applied to docker containers. It understands the following:

`com.chameth.auth`::
Specifies the name of an auth group (which must be defined in the DOTEGE_USERS env variable)
that users are required to be in to access the container. See <<acls,Using ACLs>> below for
detailed usage.

`com.chameth.headers`::
Specifies response headers to be sent to the client for all requests to the container. Any
label with this as a prefix will be used, so multiple headers can be specified as
`com.chameth.headers.1`, or `com.chameth.headers-frame-options`, for example.

`com.chameth.proxy`::
The port on which the container is listening for requests. If `com.chameth.vhost` is specified
and `com.chameth.proxy` is not and the container exposes a single non-bound port then Dotege
will automatically use that port. That means you do not need to manually label the port for an
nginx server, for instance, as the nginx image exposes port 80 (only).

`com.chameth.proxytag`::
Arbitrary tag to control which containers an instance of Dotege will deal with. If specified,
the container will be ignored by any instance of Dotege that does not have the same value
passed in using the `DOTEGE_PROXYTAG` env var.

`com.chameth.vhost`::
Comma- or space-delimited list of hostnames that the container will handle requests for.
Certificates will have the first host as the subject, and any additional hosts will be
alternate names. Certificates are only reused if all hostnames match.

== Example compose file

[source,yaml]
----
version: '3.5'
services:
  dotege:
    image: ghcr.io/csmith/dotege
    restart: always
    volumes:
      - data:/data/config
      - certs:/data/certs
      - config:/data/output
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - DOTEGE_ACME_EMAIL=email@address
      - DOTEGE_DNS_PROVIDER=httpreq
      - DOTEGE_SIGNAL_CONTAINER=dotege_haproxy_1
      - DOTEGE_SIGNAL_TYPE=USR2
      - DOTEGE_WILDCARD_DOMAINS=mydomain.com
      - HTTPREQ_ENDPOINT=https://example.com/
      - HTTPREQ_USERNAME=user@name
      - HTTPREQ_PASSWORD=p@ssw0rd

  haproxy:
    image: haproxy:2.0.1
    restart: always
    volumes:
      - config:/usr/local/etc/haproxy:ro
      - certs:/certs:ro
    ports:
      - 443:443
      - 80:80
    networks:
      - web

networks:
  web:
    external: true

volumes:
  data:
  certs:
  config:
----

This creates an instance of Dotege, configured to use `httpreq` to perform DNS
operations in order to generate SSL certificates. You can see the list of
supported providers and their required environment variables in the
https://go-acme.github.io/lego/dns/[Lego docs].

The haproxy instance has read-only access to the config and certs volumes that
will be populated by Dotege, and Dotege will send it the `USR2` signal whenever
the config or certs change. With the default haproxy image this will cause it
to reload the configuration.

Container names must be resolvable from the haproxy container with the default
template. This means the haproxy container should be on the same network as
the containers it's proxying to. I recommend creating a global 'web' network
(or similar) that all web-facing containers sit in.

== Using ACLs [[acls]]

Dotege, with the default HAProxy template, allows you to specify users in an
environment variable and for individual containers to then require a specific
group of users using labels.

=== Defining users

Dotege expects the DOTEGE_USERS environment variable to contain a list of users,
and each user must have a "name" and "password" property, and an optional "groups"
property. For example if we want our user list to look like this:

[source,yaml]
----
- name: chris
  password: hashedPasswordHere
  groups: [admins]
- name: bob
  password: hashedPasswordHere
----

Then we'd use the following environment variable:

[source]
----
DOTEGE_USERS="- name: chris\n  password: hashedPasswordHere\n  groups: [admins]\n- name: bob\n  password: hashedPasswordHere"
----

Alternatively, removing the need for line breaks:

[source]
----
DOTEGE_USERS="[{name: chris, password: hashedPasswordHere, groups: [admins]}, {name: bob, password: hashedPasswordHere}]"
----

If you are using configuring the container using YAML (e.g. in a docker-compose file),
you can use the pipe operator to treat YAML content as a scalar, which is vastly easier to
use:

[source,yaml]
----
services:
  dotege:
    environment:
      DOTEGE_USERS: |
        - name: chris
          password: hashedPasswordHere
          groups: [admins]
        - name: bob
          password: hashedPasswordHere
----

For HAProxy, passwords are hashed using the crypt(3) system call - the easiest
way to generate them is using the `mkpassword` utility.

NB: If you are using docker-compose then any `$` characters in the hashed password
will need to be escaped by doubling them up (i.e. replace `$` with `$$`).

=== Restricting access

To require basic authentication, the container should have the `com.chameth.auth` label.
The label should be a space separated list of groups that are allowed access; if it
is blank then all defined users are allowed.

For example:

[source,yaml]
----
services:
  public:
    labels:
      com.chameth.vhost: "public.example.com"
  private1:
    labels:
      com.chameth.vhost: "private1.example.com"
      com.chameth.auth: ""
  private2:
    labels:
      com.chameth.vhost: "private2.example.com"
      com.chameth.auth: "admins"
----

Of these services, `public` won't require any authentication. `private1` will
require any valid user (so from our example above, either "chris" or "bob"),
while `private2` will require a user in the "admins" group (so from our example
above only "chris" would be allowed access).

== Writing templates

Dotege comes with two templates out of the box - one to create a working
link:templates/haproxy.cfg.tpl[HAProxy config], and one to output a
link:templates/domains.txt.tpl[list of domains] suitable for use with a
tool like https://github.com/dehydrated-io/dehydrated/[Dehydrated].

Dotege uses Go's built in https://golang.org/pkg/text/template/[text/template]
package which provides extensive documentation for the template syntax itself.
If you've used Smarty, Jinja or other templating systems the syntax should look
pretty similar.

Dotege provides the following data to templates:

* Containers - a map of container IDs to the container's details:
** Id - the ID of the container
** Headers - map of header names to values from `com.chameth.headers` labels
** Labels - map of all label names to values
** Name - the name of the container
** Port - the port the container accepts traffic on, or -1 if it couldn't be determined
** Ports - all ports exposed by the container
** ShouldProxy - boolean indicating whether the container has a hostname and port
* Groups - a list of unique group names specified in the `DOTEGE_USERS` key
* Hostnames - a map of known primary hostnames to their details:
** Alternatives - a map of alternate names for this hostname
** AuthGroup - the name of the group users must be a member of to access this hostname (if RequiresAuth is true)
** Containers - all containers that accept traffic for this hostname
** Headers - map of header names to values from `com.chameth.headers` labels
** Name - the name of the primary hostname
** RequiresAuth - boolean indicating whether authentication is required
* Users - a list of users defined in the `DOTEGE_USERS` key
** Name - the username of the user
** Password - the (hashed) password of the user
** Groups - list of groups the user belongs to

Most templates will want to act on the `Hostnames` data primarily, as this groups up
containers that accept traffic to the same domains, and avoids having to deal with
containers that aren't configured for use with Dotege.

== Build tags

If you know in advance you will only use a single DNS provider, you can use build tags to include only support
for that provider in the binary. For example to support only the `httpreq` provider you can build with
`go build -tags lego_httpreq`. See the https://github.com/csmith/legotapas[legotapas] project for more
info.

== Contributing

Contributions are welcome! Please raise an issue if you have any feature requests or spot a bug, or open a pull
request if you want to suggest any code changes.

== Licence and credits

Dotege is licensed under the MIT licence. A full copy of the licence is available in
the link:LICENCE[LICENCE] file.

Dotege makes use of a number of third-party libraries. See the link:go.mod[go.mod] file
for a list of direct dependencies. Users of the docker image will find a copy of the
relevant licence and notice files under the `/notices` directory in the image.

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

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