1
0
Fork 0

ACME Docs and changes in Functions.run_bash

This commit is contained in:
Joao Gilberto Magalhaes 2023-07-02 02:07:37 -05:00
parent 014f83332c
commit 9db4d763ec
13 changed files with 127 additions and 99 deletions

View file

@ -19,11 +19,15 @@ EasyHAProxy can detect and configure HAProxy automatically on the following plat
- Docker Swarm
- Kubernetes
## EasyHAProxy Mission
Easy to set up and low configuration to numerous features.
## Features
EasyHAProxy will discover the services based on the Docker Tags of the containers running on a Docker host or Docker Swarm cluster and dynamically set up the `haproxy.cfg`. Below, EasyHAProxy main features:
- Automatic SSL Certificate issued by any ACME compatible service as Letsencrypt and ZeroSSL
- Support Automatic Certificate Management Environment (ACME) protocol compatible with Let's encrypt and other issuers.
- Set your custom SSL certificates
- Balance traffic between multiple replicas
- Set SSL with three different levels of validations and according to the most recent definitions.
@ -59,6 +63,13 @@ Or you can install using tools:
[![MicroK8s](docs/easyhaproxy_microk8s.png)](docs/microk8s.md)
[![Dokku](docs/easyhaproxy_dokku.png)](docs/dokku.md)
## Special Topics
If you already set up the EasyHAProxy, is time to go deeper:
- [Custom SSL](docs/ssl.md)
- Automatic Certificate Issuing (e.g. Let's Encrypt)
## See EasyHAProxy in action
Click on the image to see the videos (use HD for better visualization)

36
docs/acme.md Normal file
View file

@ -0,0 +1,36 @@
# SSL - Automatic Certificate Management Environment (ACME)
The Automatic Certificate Management Environment (ACME) protocol
allow automating interactions between certificate authorities and their users' servers,
allowing the automated deployment of public key infrastructure.
Most of the issuers offers Automatic Issuing free of cost.
To enable the ACME protocol we need to enable Certbot in EasyHAProxy by setting up to 4 environment variables:
- EASYHAPROXY_CERTBOT_AUTOCONFIG (optional): Will use pre-sets for your Certificate Authority (CA). See table below.
- EASYHAPROXY_CERTBOT_EMAIL (required): Your email in the certificate authority.
- EASYHAPROXY_CERTBOT_SERVER (optional): The ACME Endpoint of your certificate authority. If you use AUTOCONFIG, it is set automatically. See table below.
- EASYHAPROXY_CERTBOT_EAB_KID (optional): External Account Binding (EAB) Key Identifier (KID) provided by your certificate authority. Some CA require it. See table below.
- EASYHAPROXY_CERTBOT_EAB_HMAC_KEY (optional): External Account Binding (EAB) HMAC Key provided by your certificate authority. Some CA require it. See table below.
Here are detailed instructions per Certificate Authority (CA). If anyone is missing, please let's know.
| CA | Auto Config | Free? | Account Required? | EAB KID? | EAB HMAC Key? | More Info |
|----------------------|------------------|-------|--------------------|----------|---------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Let's Encrypt | - | Yes | No | No | No | [Link](letsencrypt.md) |
| Let's Encrypt (Test) | letsencrypt_test | Yes | No | No | No | [Link](letsencrypt.md) |
| ZeroSSL | zerossl | Yes | No | No | No | [Link](https://zerossl.com/documentation/acme/) |
| BuyPass | buypass | Yes | No | No | No | [Link](https://community.buypass.com/t/63d4ay/buypass-go-ssl-endpoints-updated-14-05-2020) |
| BuyPass (test) | buypass_test | Yes | No | No | No | [Link](https://community.buypass.com/t/63d4ay/buypass-go-ssl-endpoints-updated-14-05-2020) |
| Google | google | Yes | Yes | Yes | Yes | [Link](https://cloud.google.com/blog/products/identity-security/automate-public-certificate-lifecycle-management-via--acme-client-api) |
| Google Test | google_test | Yes | Yes | Yes | Yes | [Link](https://cloud.google.com/blog/products/identity-security/automate-public-certificate-lifecycle-management-via--acme-client-api) |
| SSLCOM RCA | sslcom_rca | Yes | No. Keys by email. | Yes | Yes | [Link](https://www.ssl.com/blogs/sslcom-supports-acme-protocol-ssl-tls-certificate-automation/) |
| SSLCOM ECC | sslcom_ecc | Yes | No. Keys by email. | Yes | Yes | [Link](https://www.ssl.com/blogs/sslcom-supports-acme-protocol-ssl-tls-certificate-automation/) |
| Digicert | - | No | Yes | Yes | Yes | [Link](https://docs.digicert.com/en/certcentral/certificate-tools/certificate-lifecycle-automation-guides/use-a-third-party-acme-client-for-host-automations.html) |
| Entrust | - | No | Yes | Yes | Yes | [Link](https://www.entrust.com/knowledgebase/ssl/how-to-use-acme-to-install-ssl-tls-certificates-in-entrust-certificate-services-apache) |
| Sectigo | - | No | Yes | Yes | Yes | [Link](https://www.sectigo.com/resource-library/sectigos-acme-automation) |
This configuration is global. After set up ACME properly, is necessary enable for each domain the certificate request.
To do that add the label: `easyhaproxy.<definition>.certbot=true`. See the method of installation you are using to learn how to set up properly.

View file

@ -12,7 +12,7 @@
| easyhaproxy.[definition].sslcert | (Optional) Cert PEM Base64 encoded. Do not use this if `certbot` is enabled. | *empty* | base64 cert + key |
| easyhaproxy.[definition].ssl | (Optional) If `true` you need to provide certificate as a file. See below. Do not use with `sslcert`. | false | true or false |
| easyhaproxy.[definition].health-check | (Optional) `ssl`, enable health check via SSL in `mode tcp` | *empty* | ssl |
| easyhaproxy.[definition].certbot | (Optional) Generate certificate with certbot. Do not use with `sslcert` parameter. | false | true OR false |
| easyhaproxy.[definition].certbot | (Optional) Generate certificate with certbot. Do not use with `sslcert` parameter. More info [here](acme.md). | false | true OR false |
| easyhaproxy.[definition].redirect_ssl | (Optional) Redirect all requests to https | false | true OR false |
| easyhaproxy.[definition].clone_to_ssl | (Optional) It copies the configuration to HTTPS(443) and disable SSL from the current config. **Do not use* this with `ssl` or `certbot` parameters | false | true OR false |

View file

@ -54,13 +54,9 @@ Please follow the [docker label configuration](container-labels.md) to see other
You can configure the behavior of the EasyHAProxy by setup specific environment variables. To get a list of the variables, please follow the [docker container environment](docker-environment.md)
## Setup certificates with Letsencrypt
## Setup certificates with ACME (e.g. Letsencrypt)
Follow [this link](letsencrypt.md)
## Setup certificates with ZeroSSL
Follow [this link](zerossl.md)
Follow [this link](acme.md)
## Setup your own certificates

View file

@ -90,7 +90,7 @@ Caveats:
**Important**: The annotations are per ingress and applied to all hosts in that ingress configuration.
## Letsencrypt
## Certbot / ACME / Letsencrypt
It is necessary add the annotation `easyhaproxy.certbot` to the ingress configuration:
@ -106,6 +106,8 @@ spec:
....
```
More info [here](acme.md).
Make sure your cluster is accessible both through ports 80 and 443.
## Custom SSL Certificates

View file

@ -1,6 +1,6 @@
# Setup custom certificates
You can use your certificates with EasyHAProxy.
You can use your own certificates with EasyHAProxy. You just need to let EasyHAProxy know that certificate.
There are two ways to do that.

View file

@ -1,70 +0,0 @@
# ZeroSSL
EasyHAProxy can issue a ZeroSSL certificate. Follow the steps below:
## Getting the Keys from ZeroSSL
- Login to [ZeroSSL](https://zerossl.com?fpr=byjg)
- If you don't have an account you can use our referral link: [https://zerossl.com?fpr=byjg](https://zerossl.com?fpr=byjg)
- If you created recently and would like to support us open an issue, and I'll try to add you as our referred.
- In the ZeroSSL dashboard click in 'Developer' and the Generate EAB Keys
![zerossl_1.png](zerossl_1.png)
- Once you generate the keys, please **take note**. We will need this later, and it isn't saved anywhere.
![zerossl_2.png](zerossl_2.png)
```text
Important: if you to this process again the old values will be lost and you need to setup EasyHAProxy again.
```
## Setting up EasyHAProxy
Run the EasyHAProxy container with the following parameters:
```bash
docker run \
... \
-e EASYHAPROXY_CERTBOT_EMAIL="your zerossl email" \
-e EASYHAPROXY_CERTBOT_EAB_KID="the eab_kid from the previous step" \
-e EASYHAPROXY_CERTBOT_EAB_HMAC_KEY="the eab_hmac_key from the previous step" \
-e EASYHAPROXY_CERTBOT_SERVER="https://acme.zerossl.com/v2/DV90" \
-p 80:80 \
-p 443:443 \
-v /path/to/guest/certbot/certs:/certs/certbot \
... \
byjg/easy-haproxy
```
Notes:
- If you don't setup all `EASYHAPROXY_CERTBOT_*` environment variables with the proper values, EasyHAProxy will fail silently and **will not request** a certificate.
- The ports 80 and 443 needs to accessible through the internet as [Let's Encrypt requirement](https://letsencrypt.org/docs/allow-port-80/)
**It is required you to persist the container folder `/certs/certbot` outside the container.**
You cannot delete or change it contents.
If you do not persist, or change/delete the contents, Let's encrypt will not work properly.
## Setting up your container to use ZeroSSL
```bash
docker run \
... \
--label easyhaproxy.express.port=80 \
--label easyhaproxy.express.localport=3000 \
--label easyhaproxy.express.host=example.org \
--label easyhaproxy.express.certbot=true \
... \
some/myimage
```
Requirements:
- Your container **must** listen to port 80. Letsencrypt will not issue the certificate if `easyhaproxy.<definition>.port` is in another port, and EasyHAProxy will fail silently.
- You cannot set port 443 for the container with the Letsencrypt because EasyHAProxy will create this port automatically once the certificate is issued.
----
[Open source ByJG](http://opensource.byjg.com)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

View file

@ -28,7 +28,7 @@ class ContainerEnv:
"EASYHAPROXY_LABEL_PREFIX") else "easyhaproxy"
env_vars["certbot"] = {
"autoconfig": os.getenv("EASYHAPROXY_CERTBOT_AUTOCONFIG", "letsencrypt"),
"autoconfig": os.getenv("EASYHAPROXY_CERTBOT_AUTOCONFIG", ""),
"email": os.getenv("EASYHAPROXY_CERTBOT_EMAIL", ""),
"server": os.getenv("EASYHAPROXY_CERTBOT_SERVER", False),
"eab_kid": os.getenv("EASYHAPROXY_CERTBOT_EAB_KID", ""),
@ -164,8 +164,9 @@ class Functions:
Functions.log(source, Functions.WARN, process.stderr.readlines())
break
return output
return [return_code, output]
except Exception as e:
return [-99, e]
Functions.log(source, Functions.ERROR, "%s" % e)

7
src/tests/fixtures/run_bash.sh vendored Executable file
View file

@ -0,0 +1,7 @@
#!/bin/bash
# Just return the exit code
echo "Processing run_bash.sh"
if [ -n "$1" ]; then
exit "$1"
fi

View file

@ -8,7 +8,7 @@ def test_container_env_empty():
"customerrors": False,
"ssl_mode": "default",
"lookup_label": "easyhaproxy",
"certbot": {"autoconfig": "letsencrypt",
"certbot": {"autoconfig": "",
"eab_hmac_key": "",
"eab_kid": "",
"email": "",
@ -25,7 +25,7 @@ def test_container_env_customerrors():
"customerrors": True,
"ssl_mode": "default",
"lookup_label": "easyhaproxy",
"certbot": {"autoconfig": "letsencrypt",
"certbot": {"autoconfig": "",
"eab_hmac_key": "",
"eab_kid": "",
"email": "",
@ -42,7 +42,7 @@ def test_container_env_sslmode():
"customerrors": False,
"ssl_mode": "strict",
"lookup_label": "easyhaproxy",
"certbot": {"autoconfig": "letsencrypt",
"certbot": {"autoconfig": "",
"eab_hmac_key": "",
"eab_kid": "",
"email": "",
@ -60,7 +60,7 @@ def test_container_env_stats():
"customerrors": False,
"ssl_mode": "default",
"lookup_label": "easyhaproxy",
"certbot": {"autoconfig": "letsencrypt",
"certbot": {"autoconfig": "",
"eab_hmac_key": "",
"eab_kid": "",
"email": "",
@ -84,7 +84,7 @@ def test_container_env_stats_password():
"port": "1936"
},
"certbot": {"autoconfig": "letsencrypt",
"certbot": {"autoconfig": "",
"eab_hmac_key": "",
"eab_kid": "",
"email": "",
@ -108,7 +108,7 @@ def test_container_env_stats_password_2():
"password": "xyz",
"port": "2101"
},
"certbot": {"autoconfig": "letsencrypt",
"certbot": {"autoconfig": "",
"eab_hmac_key": "",
"eab_kid": "",
"email": "",
@ -128,11 +128,11 @@ def test_container_env_certbot_email():
"ssl_mode": "default",
"lookup_label": "easyhaproxy",
"certbot": {
"autoconfig": "letsencrypt",
"autoconfig": "",
'eab_hmac_key': "",
'eab_kid': "",
"email": "acme@example.org",
"server": 'https://acme-v02.api.letsencrypt.org/directory'
"server": False
}
} == ContainerEnv.read()
finally:
@ -150,7 +150,7 @@ def test_container_env_certbot_full():
"ssl_mode": "default",
"lookup_label": "easyhaproxy",
"certbot": {
"autoconfig": "letsencrypt",
"autoconfig": "",
"email": "acme@example.org",
"server": "schema://url/a",
'eab_hmac_key': 'eab_hmac_key',

View file

@ -65,8 +65,9 @@ def test_functions_run_bash_log_output():
print()
Functions.debug_log = []
try:
result = Functions.run_bash(Functions.EASYHAPROXY_LOG, "echo 'test run 1'", log_output=True,
return_result=False)
return_code, result = Functions.run_bash(Functions.EASYHAPROXY_LOG, "echo 'test run 1'", log_output=True,
return_result=False)
assert return_code == 0
assert result == []
assert len(Functions.debug_log) == 1
assert re.match("\[EASYHAPROXY\] .* \[INFO\]: test run 1", Functions.debug_log[0])
@ -78,8 +79,9 @@ def test_functions_run_bash_no_log_output():
print()
Functions.debug_log = []
try:
result = Functions.run_bash(Functions.EASYHAPROXY_LOG, "echo 'test run 2'", log_output=False,
return_result=False)
return_code, result = Functions.run_bash(Functions.EASYHAPROXY_LOG, "echo 'test run 2'", log_output=False,
return_result=False)
assert return_code == 0
assert result == []
assert len(Functions.debug_log) == 0
finally:
@ -90,8 +92,9 @@ def test_functions_run_bash_return():
print()
Functions.debug_log = []
try:
result = Functions.run_bash(Functions.EASYHAPROXY_LOG, "echo 'test run 3'", log_output=False,
return_result=True)
return_code, result = Functions.run_bash(Functions.EASYHAPROXY_LOG, "echo 'test run 3'", log_output=False,
return_result=True)
assert return_code == 0
assert len(Functions.debug_log) == 0
assert "".join(result) == 'test run 3'
finally:
@ -102,9 +105,51 @@ def test_functions_run_bash_log_and_return_output():
print()
Functions.debug_log = []
try:
result = Functions.run_bash(Functions.EASYHAPROXY_LOG, "echo 'test run 4'", log_output=True, return_result=True)
return_code, result = Functions.run_bash(Functions.EASYHAPROXY_LOG, "echo 'test run 4'", log_output=True, return_result=True)
assert return_code == 0
assert "".join(result) == 'test run 4'
assert len(Functions.debug_log) == 1
assert re.match("\[EASYHAPROXY\] .* \[INFO\]: test run 4", Functions.debug_log[0])
finally:
Functions.debug_log = None
def test_functions_run_bash_ok():
print()
Functions.debug_log = []
try:
return_code, result = Functions.run_bash(Functions.EASYHAPROXY_LOG, "%s/fixtures/run_bash.sh" % os.path.dirname(__file__), log_output=True,
return_result=False)
assert return_code == 0
assert result == []
assert len(Functions.debug_log) == 1
assert re.match("\[EASYHAPROXY\] .* \[INFO\]: Processing run_bash.sh", Functions.debug_log[0])
finally:
Functions.debug_log = None
def test_functions_run_bash_fail():
print()
Functions.debug_log = []
try:
return_code, result = Functions.run_bash(Functions.EASYHAPROXY_LOG, "%s/fixtures/run_bash.sh 15" % os.path.dirname(__file__), log_output=True,
return_result=False)
assert return_code == 15
assert result == []
assert len(Functions.debug_log) == 1
assert re.match("\[EASYHAPROXY\] .* \[INFO\]: Processing run_bash.sh", Functions.debug_log[0])
finally:
Functions.debug_log = None
def test_functions_run_command_not_found():
print()
Functions.debug_log = []
try:
return_code, result = Functions.run_bash(Functions.EASYHAPROXY_LOG, "no_command_here", log_output=True,
return_result=False)
assert return_code == -99
assert str(result) == "[Errno 2] No such file or directory: 'no_command_here'"
assert len(Functions.debug_log) == 0
finally:
Functions.debug_log = None