120 lines
4.2 KiB
Python
120 lines
4.2 KiB
Python
"""HAProxy Authenticator.
|
|
|
|
The HAProxy Authenticator is an extension of the "standalone" authenticator
|
|
that is part of certbot. It limits its functionality to only support the
|
|
`http-01` challenge because `tls-sni-01` checks the challenge by connecting to
|
|
port 443. We can't proxy requests to certbot because we can't see the
|
|
requested uri until the request is decrypted, and we can't do decryption in
|
|
HAProxy because `tls-sni-01` expects to do a TLS handshake.
|
|
|
|
This authenticator creates its own ephemeral TCP listener on the necessary port
|
|
in order to respond to incoming `http-01` challenges from the certificate
|
|
authority. You need to forward port requests for `/.well-known/acme-challenge/`
|
|
on port 80 to the configured value for `haproxy-http-01-port` (default:8000).
|
|
This can be achieved by adding this example to your haproxy configuration
|
|
file::
|
|
|
|
default_backend nodes
|
|
|
|
acl is_certbot path_beg -i /.well-known/acme-challenge
|
|
use_backend certbot if is_certbot
|
|
|
|
backend certbot
|
|
log global
|
|
mode http
|
|
server certbot 127.0.0.1:8000
|
|
|
|
backend nodes
|
|
log global
|
|
mode http
|
|
option tcplog
|
|
balance roundrobin
|
|
option forwardfor
|
|
option http-server-close
|
|
option httpclose
|
|
http-request set-header X-Forwarded-Port %[dst_port]
|
|
http-request add-header X-Forwarded-Proto https if { ssl_fc }
|
|
option httpchk HEAD / HTTP/1.1\\r\\nHost:localhost
|
|
server node1 127.0.0.1:8080 check
|
|
server node2 127.0.0.1:8080 check
|
|
server node3 127.0.0.1:8080 check
|
|
server node4 127.0.0.1:8080 check
|
|
|
|
For instructions on how to make HAProxy serve certificates that were created
|
|
with this authenticator, read the documentation of the
|
|
`.certbot_haproxy.installer`
|
|
"""
|
|
import logging
|
|
|
|
import zope.component
|
|
import zope.interface
|
|
|
|
from acme import challenges
|
|
|
|
from certbot import interfaces
|
|
from certbot.plugins import standalone
|
|
|
|
logger = logging.getLogger(__name__) # pylint:disable=invalid-name
|
|
|
|
|
|
@zope.interface.implementer(interfaces.IAuthenticator)
|
|
@zope.interface.provider(interfaces.IPluginFactory)
|
|
class HAProxyAuthenticator(standalone.Authenticator):
|
|
"""HAProxy Authenticator."""
|
|
|
|
description = "Certbot standalone authenticator with HAProxy preset."
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super(HAProxyAuthenticator, self).__init__(*args, **kwargs)
|
|
self.config.http01_port = self.conf('haproxy_http_01_port')
|
|
|
|
@classmethod
|
|
def add_parser_arguments(cls, add):
|
|
"""
|
|
This method adds extra CLI arguments to the plugin.
|
|
The arguments can be retrieved by asking for corresponding names
|
|
in `self.conf([argument name])`
|
|
|
|
.. note:: This overrides a method defined in the parent, we
|
|
are deliberately not calling super() because it would add
|
|
arguments that are not supported.
|
|
|
|
:param func add: The function to be called to add an argument.
|
|
"""
|
|
add(
|
|
"haproxy-http-01-port",
|
|
help=(
|
|
"Port to open internally (default=8000), you're expected to"
|
|
" forward requests to port 80 to it."
|
|
),
|
|
type=int,
|
|
default=8000
|
|
)
|
|
|
|
@property
|
|
def supported_challenges(self):
|
|
"""
|
|
Challenges supported by this plugin: only http-01
|
|
See introduction for reasoning.
|
|
|
|
:returns: List of supported challenges
|
|
:rtype: list
|
|
"""
|
|
return [challenges.HTTP01]
|
|
|
|
@staticmethod
|
|
def more_info():
|
|
"""
|
|
This info string only appears in the curses UI in the plugin
|
|
selection sequence.
|
|
"""
|
|
return (
|
|
"This authenticator creates its own ephemeral TCP listener"
|
|
" on the configured internal port (default=8000) in order to"
|
|
" respond to incoming http-01 challenges from the certificate"
|
|
" authority. In order for this port to be reached, you need to"
|
|
" configure HAProxy to forward any requests to any domain on the"
|
|
" http-01 port (default:80), ending in"
|
|
" `/.well-known/acme-challenge/` to the http-01 port (hint:8000)."
|
|
)
|