1
0
mirror of https://github.com/moepman/acertmgr.git synced 2025-01-01 04:21:51 +01:00

configuration: Force user to agree to the authorities Terms of Service

Authorities (e.g. Let's Encrypt) usually have Terms of Serivce (ToS)
that have to be agreed to. Up until this point we automatically
indicated agreement to those ToS and sent the necessary value.

This commit changes the behaviour to be in line with recommendations
from Let's Encrypt that the user themselves have to indicate their
agreement by no longer automatically doing so (except for cases of
legacy configuration files to provide compatibility).

The user can now indicate ToS agreement by either setting the associated
configuration variable (authority_tos_agreement) to the required value
and/or providing the required value via a command-line parameter
(--authority-tos-agreement=<value>/--tos-agreement=<value>/--tos=<value>)
This commit is contained in:
Kishi85 2019-03-20 10:34:59 +01:00
parent 784badf54b
commit 316ecdba2e
5 changed files with 26 additions and 13 deletions

View File

@ -41,6 +41,8 @@ You can optionally provide the key files for the ACME protocol, if you do not th
Finally, you need to setup the configuration files, as shown in the next section. Finally, you need to setup the configuration files, as shown in the next section.
While testing, you can use the acme-staging authority instead, in order to avoid issuing too many certificates. While testing, you can use the acme-staging authority instead, in order to avoid issuing too many certificates.
Authorities (e.g. our default Let's Encrypt) will require you to accept their Terms of Service. This can be done either in the optional global config file and/or via a commandline parameter (see acertmgr.py --help).
Configuration Configuration
------------- -------------
@ -58,12 +60,12 @@ All configuration files can use yaml (requires PyYAML) or json syntax.
#api: v1 #api: v1
#authority: "https://acme-v01.api.letsencrypt.org" #authority: "https://acme-v01.api.letsencrypt.org"
#authority: "https://acme-staging.api.letsencrypt.org" #authority: "https://acme-staging.api.letsencrypt.org"
#authority_agreement: "https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf" #authority_tos_agreement: "https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf"
# Current (default) ACME v2 API with options: # Current (default) ACME v2 API with options:
#api: v2 #api: v2
#authority: "https://acme-v02.api.letsencrypt.org" #authority: "https://acme-v02.api.letsencrypt.org"
#authority: "https://acme-staging-v02.api.letsencrypt.org" #authority: "https://acme-staging-v02.api.letsencrypt.org"
#authority_agreement: "True" # Indicates you agree to the ToS stated by the API provider authority_tos_agreement: "true" # Indicates you agree to the ToS stated by the API provider
#authority_contact_email: "foo@b.ar" # For single addresses #authority_contact_email: "foo@b.ar" # For single addresses
#authority_contact_email: # For multiple addresses #authority_contact_email: # For multiple addresses
# - "foo@b.ar" # - "foo@b.ar"

View File

@ -35,7 +35,7 @@ class ACMEAuthority(AbstractACMEAuthority):
def __init__(self, config, key): def __init__(self, config, key):
AbstractACMEAuthority.__init__(self, config, key) AbstractACMEAuthority.__init__(self, config, key)
self.ca = config['authority'] self.ca = config['authority']
self.agreement = config['authority_agreement'] self.agreement = config['authority_tos_agreement']
# @brief create the header information for ACME communication # @brief create the header information for ACME communication
# @param key the account key # @param key the account key

View File

@ -34,7 +34,7 @@ class ACMEAuthority(AbstractACMEAuthority):
AbstractACMEAuthority.__init__(self, config, key) AbstractACMEAuthority.__init__(self, config, key)
# Initialize config vars # Initialize config vars
self.ca = config['authority'] self.ca = config['authority']
self.agreement = str(config.get('authority_agreement')) == 'true' self.tos_agreed = str(config.get('authority_tos_agreement')).lower() == 'true'
contact_email = config.get('authority_contact_email') contact_email = config.get('authority_contact_email')
if contact_email is None: if contact_email is None:
self.contact = None self.contact = None
@ -128,7 +128,7 @@ class ACMEAuthority(AbstractACMEAuthority):
def register_account(self): def register_account(self):
protected = copy.deepcopy(self.account_protected) protected = copy.deepcopy(self.account_protected)
payload = { payload = {
"termsOfServiceAgreed": self.agreement, "termsOfServiceAgreed": self.tos_agreed,
"onlyReturnExisting": False, "onlyReturnExisting": False,
} }
if self.contact: if self.contact:

View File

@ -24,7 +24,7 @@ DEFAULT_KEY_LENGTH = 4096 # bits
DEFAULT_TTL = 30 # days DEFAULT_TTL = 30 # days
DEFAULT_API = "v2" DEFAULT_API = "v2"
DEFAULT_AUTHORITY = "https://acme-v02.api.letsencrypt.org" DEFAULT_AUTHORITY = "https://acme-v02.api.letsencrypt.org"
DEFAULT_AUTHORITY_AGREEMENT = "True" LEGACY_AUTHORITY_TOS_AGREEMENT = "true"
# @brief augment configuration with defaults # @brief augment configuration with defaults
@ -54,7 +54,7 @@ def update_config_value(config, name, localconfig, globalconfig, default):
# @brief load the configuration from a file # @brief load the configuration from a file
def parse_config_entry(entry, globalconfig, work_dir): def parse_config_entry(entry, globalconfig, work_dir, authority_tos_agreement):
config = dict() config = dict()
# Basic domain information # Basic domain information
@ -71,8 +71,8 @@ def parse_config_entry(entry, globalconfig, work_dir):
# Certificate authority # Certificate authority
update_config_value(config, 'authority', entry, globalconfig, DEFAULT_AUTHORITY) update_config_value(config, 'authority', entry, globalconfig, DEFAULT_AUTHORITY)
# Certificate authority agreement # Certificate authority ToS agreement
update_config_value(config, 'authority_agreement', entry, globalconfig, DEFAULT_AUTHORITY_AGREEMENT) update_config_value(config, 'authority_tos_agreement', entry, globalconfig, authority_tos_agreement)
# Certificate authority contact email addresses # Certificate authority contact email addresses
update_config_value(config, 'authority_contact_email', entry, globalconfig, None) update_config_value(config, 'authority_contact_email', entry, globalconfig, None)
@ -148,6 +148,8 @@ def load():
help="domain configuration directory (default='{}')".format(DEFAULT_CONF_DIR)) help="domain configuration directory (default='{}')".format(DEFAULT_CONF_DIR))
parser.add_argument("-w", "--work-dir", nargs="?", parser.add_argument("-w", "--work-dir", nargs="?",
help="persistent work data directory (default=config_dir)") help="persistent work data directory (default=config_dir)")
parser.add_argument("--authority-tos-agreement", "--tos-agreement", "--tos", nargs="?",
help="Agree to the authorities Terms of Service (value required depends on authority)")
args = parser.parse_args() args = parser.parse_args()
# Determine global configuration file # Determine global configuration file
@ -175,6 +177,15 @@ def load():
# .. or use the domain configuration directory otherwise # .. or use the domain configuration directory otherwise
work_dir = domain_config_dir work_dir = domain_config_dir
# Determine authority agreement
if args.authority_tos_agreement:
authority_tos_agreement = args.authority_tos_agreement
elif global_config_file == LEGACY_CONF_FILE:
# Old global config file assumes ToS are agreed
authority_tos_agreement = LEGACY_AUTHORITY_TOS_AGREEMENT
else:
authority_tos_agreement = None
# load global configuration # load global configuration
globalconfig = dict() globalconfig = dict()
if os.path.isfile(global_config_file): if os.path.isfile(global_config_file):
@ -203,11 +214,11 @@ def load():
try: try:
import json import json
for entry in json.load(config_fd).items(): for entry in json.load(config_fd).items():
config.append(parse_config_entry(entry, globalconfig, work_dir)) config.append(parse_config_entry(entry, globalconfig, work_dir, authority_tos_agreement))
except ValueError: except ValueError:
import yaml import yaml
config_fd.seek(0) config_fd.seek(0)
for entry in yaml.safe_load(config_fd).items(): for entry in yaml.safe_load(config_fd).items():
config.append(parse_config_entry(entry, globalconfig, work_dir)) config.append(parse_config_entry(entry, globalconfig, work_dir, authority_tos_agreement))
return config return config

View File

@ -4,12 +4,12 @@
#api: v1 #api: v1
#authority: "https://acme-v01.api.letsencrypt.org" #authority: "https://acme-v01.api.letsencrypt.org"
#authority: "https://acme-staging.api.letsencrypt.org" #authority: "https://acme-staging.api.letsencrypt.org"
#authority_agreement: "https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf" #authority_tos_agreement: "https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf"
# Current (default) ACME v2 API with options: # Current (default) ACME v2 API with options:
#api: v2 #api: v2
#authority: "https://acme-v02.api.letsencrypt.org" #authority: "https://acme-v02.api.letsencrypt.org"
#authority: "https://acme-staging-v02.api.letsencrypt.org" #authority: "https://acme-staging-v02.api.letsencrypt.org"
#authority_agreement: "True" # Indicates you agree to the ToS stated by the API provider authority_tos_agreement: "true" # Indicates you agree to the ToS stated by the API provider
#authority_contact_email: "foo@b.ar" # For single addresses #authority_contact_email: "foo@b.ar" # For single addresses
#authority_contact_email: # For multiple addresses #authority_contact_email: # For multiple addresses
# - "foo@b.ar" # - "foo@b.ar"