diff --git a/docs/ENVIRONMENT.rst b/docs/ENVIRONMENT.rst index 6ca5500b..618497aa 100644 --- a/docs/ENVIRONMENT.rst +++ b/docs/ENVIRONMENT.rst @@ -162,6 +162,7 @@ REST API - **PATRONI\_RESTAPI\_PASSWORD**: Basic-auth password to protect unsafe REST API endpoints. - **PATRONI\_RESTAPI\_CERTFILE**: Specifies the file with the certificate in the PEM format. If the certfile is not specified or is left empty, the API server will work without SSL. - **PATRONI\_RESTAPI\_KEYFILE**: Specifies the file with the secret key in the PEM format. +- **PATRONI\_RESTAPI\_KEYFILE\_PASSWORD**: Specifies a password for decrypting the keyfile. - **PATRONI\_RESTAPI\_CAFILE**: Specifies the file with the CA_BUNDLE with certificates of trusted CAs to use while verifying client certs. - **PATRONI\_RESTAPI\_CIPHERS**: (optional) Specifies the permitted cipher suites (e.g. "ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256:!SSLv1:!SSLv2:!SSLv3:!TLSv1:!TLSv1.1") - **PATRONI\_RESTAPI\_VERIFY\_CLIENT**: ``none`` (default), ``optional`` or ``required``. When ``none`` REST API will not check client certificates. When ``required`` client certificates are required for all REST API calls. When ``optional`` client certificates are required for all unsafe REST API endpoints. When ``required`` is used, then client authentication succeeds, if the certificate signature verification succeeds. For ``optional`` the client cert will only be checked for ``PUT``, ``POST``, ``PATCH``, and ``DELETE`` requests. diff --git a/docs/SETTINGS.rst b/docs/SETTINGS.rst index 4b1036fc..cce1bd6f 100644 --- a/docs/SETTINGS.rst +++ b/docs/SETTINGS.rst @@ -321,6 +321,7 @@ REST API - **password**: Basic-auth password to protect unsafe REST API endpoints. - **certfile**: (optional): Specifies the file with the certificate in the PEM format. If the certfile is not specified or is left empty, the API server will work without SSL. - **keyfile**: (optional): Specifies the file with the secret key in the PEM format. + - **keyfile_password**: (optional): Specifies a password for decrypting the keyfile. - **cafile**: (optional): Specifies the file with the CA_BUNDLE with certificates of trusted CAs to use while verifying client certs. - **ciphers**: (optional): Specifies the permitted cipher suites (e.g. "ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256:!SSLv1:!SSLv2:!SSLv3:!TLSv1:!TLSv1.1") - **verify\_client**: (optional): ``none`` (default), ``optional`` or ``required``. When ``none`` REST API will not check client certificates. When ``required`` client certificates are required for all REST API calls. When ``optional`` client certificates are required for all unsafe REST API endpoints. When ``required`` is used, then client authentication succeeds, if the certificate signature verification succeeds. For ``optional`` the client cert will only be checked for ``PUT``, ``POST``, ``PATCH``, and ``DELETE`` requests. diff --git a/patroni/api.py b/patroni/api.py index ffcb673c..2950745b 100644 --- a/patroni/api.py +++ b/patroni/api.py @@ -636,7 +636,8 @@ class RestApiServer(ThreadingMixIn, HTTPServer, Thread): ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH, cafile=ssl_options.get('cafile')) if ssl_options.get('ciphers'): ctx.set_ciphers(ssl_options['ciphers']) - ctx.load_cert_chain(certfile=ssl_options['certfile'], keyfile=ssl_options.get('keyfile')) + ctx.load_cert_chain(certfile=ssl_options['certfile'], keyfile=ssl_options.get('keyfile'), + password=ssl_options.get('keyfile_password')) verify_client = ssl_options.get('verify_client') if verify_client: modes = {'none': ssl.CERT_NONE, 'optional': ssl.CERT_OPTIONAL, 'required': ssl.CERT_REQUIRED} @@ -675,7 +676,8 @@ class RestApiServer(ThreadingMixIn, HTTPServer, Thread): if 'listen' not in config: # changing config in runtime raise ValueError('Can not find "restapi.listen" config') - ssl_options = {n: config[n] for n in ('certfile', 'keyfile', 'cafile', 'ciphers') if n in config} + ssl_options = {n: config[n] for n in ('certfile', 'keyfile', 'keyfile_password', + 'cafile', 'ciphers') if n in config} self.http_extra_headers = config.get('http_extra_headers') or {} self.http_extra_headers.update((config.get('https_extra_headers') or {}) if ssl_options.get('certfile') else {}) diff --git a/patroni/config.py b/patroni/config.py index 91acc540..b6376906 100644 --- a/patroni/config.py +++ b/patroni/config.py @@ -265,8 +265,9 @@ class Config(object): if value: ret[section][param] = value - _set_section_values('restapi', ['listen', 'connect_address', 'certfile', 'keyfile', 'cafile', 'ciphers', - 'verify_client', 'http_extra_headers', 'https_extra_headers']) + _set_section_values('restapi', ['listen', 'connect_address', 'certfile', 'keyfile', 'keyfile_password', + 'cafile', 'ciphers', 'verify_client', 'http_extra_headers', + 'https_extra_headers']) _set_section_values('ctl', ['insecure', 'cacert', 'certfile', 'keyfile']) _set_section_values('postgresql', ['listen', 'connect_address', 'config_dir', 'data_dir', 'pgpass', 'bin_dir']) _set_section_values('log', ['level', 'traceback_level', 'format', 'dateformat', 'max_queue_size',