|
@@ -1,7 +1,22 @@
|
|
|
|
+# This file is part of acme-updater, written by Helmut Pozimski 2016-2017.
|
|
|
|
+#
|
|
|
|
+# stov is free software: you can redistribute it and/or modify
|
|
|
|
+# it under the terms of the GNU General Public License as published by
|
|
|
|
+# the Free Software Foundation, version 2 of the License.
|
|
|
|
+#
|
|
|
|
+# stov is distributed in the hope that it will be useful,
|
|
|
|
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
+# GNU General Public License for more details.
|
|
|
|
+#
|
|
|
|
+# You should have received a copy of the GNU General Public License
|
|
|
|
+# along with stov. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
+
|
|
|
|
+# -*- coding: utf8 -*-
|
|
|
|
+
|
|
"""
|
|
"""
|
|
collection of helper functions used in other modules of acme-updater.
|
|
collection of helper functions used in other modules of acme-updater.
|
|
"""
|
|
"""
|
|
-# -*- coding: utf8 -*-
|
|
|
|
|
|
|
|
import logging
|
|
import logging
|
|
import datetime
|
|
import datetime
|
|
@@ -20,7 +35,8 @@ LOGGER = logging.getLogger("acme-updater")
|
|
def parse_apache_vhost(file_obj):
|
|
def parse_apache_vhost(file_obj):
|
|
"""
|
|
"""
|
|
Parses a given vhost file and extracts the main domain,
|
|
Parses a given vhost file and extracts the main domain,
|
|
- the certificate file and the TLS key file.
|
|
|
|
|
|
+ the certificate file, the TLS key file and all domains contained
|
|
|
|
+ within the vhost.
|
|
|
|
|
|
:param file_obj: file obj pointing to a vhost to parse
|
|
:param file_obj: file obj pointing to a vhost to parse
|
|
:return: list of tuples with domains and found certificates
|
|
:return: list of tuples with domains and found certificates
|
|
@@ -31,13 +47,14 @@ def parse_apache_vhost(file_obj):
|
|
cert_path = ""
|
|
cert_path = ""
|
|
key_path = ""
|
|
key_path = ""
|
|
main_domain = ""
|
|
main_domain = ""
|
|
|
|
+ domains = set()
|
|
for line in file_obj:
|
|
for line in file_obj:
|
|
if "<VirtualHost" in line:
|
|
if "<VirtualHost" in line:
|
|
vhost_started = True
|
|
vhost_started = True
|
|
elif "</VirtualHost" in line and vhost_started:
|
|
elif "</VirtualHost" in line and vhost_started:
|
|
vhost_started = False
|
|
vhost_started = False
|
|
- if cert_path and key_path and main_domain:
|
|
|
|
- parsed_info.append((main_domain, cert_path, key_path))
|
|
|
|
|
|
+ if cert_path and key_path and main_domain and domains:
|
|
|
|
+ parsed_info.append((main_domain, cert_path, key_path, domains))
|
|
LOGGER.debug(
|
|
LOGGER.debug(
|
|
"Found vhost with main domain %s, certificate %s and key "
|
|
"Found vhost with main domain %s, certificate %s and key "
|
|
"file %s", main_domain, cert_path, key_path)
|
|
"file %s", main_domain, cert_path, key_path)
|
|
@@ -46,10 +63,14 @@ def parse_apache_vhost(file_obj):
|
|
main_domain = ""
|
|
main_domain = ""
|
|
elif "ServerName" in line:
|
|
elif "ServerName" in line:
|
|
main_domain = line.strip().rsplit()[1]
|
|
main_domain = line.strip().rsplit()[1]
|
|
|
|
+ domains.add(line.strip().rsplit()[1])
|
|
elif "SSLCertificateFile" in line:
|
|
elif "SSLCertificateFile" in line:
|
|
cert_path = line.strip().rsplit()[1]
|
|
cert_path = line.strip().rsplit()[1]
|
|
elif "SSLCertificateKeyFile" in line:
|
|
elif "SSLCertificateKeyFile" in line:
|
|
key_path = line.strip().rsplit()[1]
|
|
key_path = line.strip().rsplit()[1]
|
|
|
|
+ elif "ServerAlias" in line:
|
|
|
|
+ for domain in line.strip().rsplit()[1].split(" "):
|
|
|
|
+ domains.add(domain)
|
|
return parsed_info
|
|
return parsed_info
|
|
|
|
|
|
|
|
|
|
@@ -228,3 +249,39 @@ def update_tlsa_record(zone, tlsa_port, digest, keyring, keyalgorithm,
|
|
update.replace(tlsa_record, ttl, "tlsa", tlsa_content)
|
|
update.replace(tlsa_record, ttl, "tlsa", tlsa_content)
|
|
response = dns.query.tcp(update, 'localhost')
|
|
response = dns.query.tcp(update, 'localhost')
|
|
return response
|
|
return response
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+def get_log_level(input_level=""):
|
|
|
|
+ """
|
|
|
|
+ Determines the log level to use based on a string.
|
|
|
|
+
|
|
|
|
+ :param input_level: String representing the desired log level.
|
|
|
|
+ :type input_level: str
|
|
|
|
+ :return: corresponding log level of the logging module
|
|
|
|
+ :rtype: int
|
|
|
|
+ """
|
|
|
|
+ if input_level.lower() == "debug":
|
|
|
|
+ return logging.DEBUG
|
|
|
|
+ elif input_level.lower() == "error":
|
|
|
|
+ return logging.ERROR
|
|
|
|
+ else:
|
|
|
|
+ return logging.INFO
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+def create_tlsa_records(domain, port, certificate, named_key_path):
|
|
|
|
+ """
|
|
|
|
+ Creates tlsa records for the specified (sub-)domain
|
|
|
|
+
|
|
|
|
+ :param domain: (sub-)domain the records are to be created for
|
|
|
|
+ :type domain: str
|
|
|
|
+ :param port: port to use for the record
|
|
|
|
+ :type port: str
|
|
|
|
+ :param certificate: certificate object used for record creation
|
|
|
|
+ :type certificate: OpenSSL.crypto.X509
|
|
|
|
+ :param named_key_path: path to the named session key
|
|
|
|
+ :type named_key_path: str
|
|
|
|
+ """
|
|
|
|
+ hash_digest = create_tlsa_hash(certificate)
|
|
|
|
+ zone = "%s.%s" % (domain.split(".")[-2], domain.split(".")[-1])
|
|
|
|
+ tsig, keyalgo = get_tsig_key(named_key_path)
|
|
|
|
+ update_tlsa_record(zone, port, hash_digest, tsig, keyalgo, domain)
|