linux-system-roles / certificate Goto Github PK
View Code? Open in Web Editor NEWRole for managing TLS/SSL certificate issuance and renewal
Home Page: https://linux-system-roles.github.io/certificate/
License: MIT License
Role for managing TLS/SSL certificate issuance and renewal
Home Page: https://linux-system-roles.github.io/certificate/
License: MIT License
IMHO it would be a nice and useful feature for this role to support RFC8555-compliant CAs like Let's Encrypt.
With this feature users who don't have a Free IPA CA could request valid X.509 domain certificates.
What do you think about this proposal?
Currently issuing certs using certmonger provider in any location out of /etc/pki/tls/
is not working when selinux is enforced.
Yes Open
failed: [192.168.124.91] (item={'name': 'mycert', 'common_name': 'My Certificate with SAN', 'dns': ['sub1.example.com', 'www.example.com', 'sub2.example.com', 'sub3.example.com'], 'ip': ['192.0.2.12', '198.51.100.65', '2001:db8::2:1'], 'email': ['[email protected]', '[email protected]'], 'ca': 'self-sign'}) => {
"ansible_loop_var": "item",
"changed": false,
"item": {
"ca": "self-sign",
"common_name": "My Certificate with SAN",
"dns": [
"sub1.example.com",
"www.example.com",
"sub2.example.com",
"sub3.example.com"
],
"email": [
"[email protected]",
"[email protected]"
],
"ip": [
"192.0.2.12",
"198.51.100.65",
"2001:db8::2:1"
],
"name": "mycert"
},
"module_stderr": "Shared connection to 192.168.124.91 closed.\r\n",
"module_stdout": "Traceback (most recent call last):\r\n File \"/home/scampos/.ansible/tmp/ansible-tmp-1595255035.770431-964964-95331819209089/AnsiballZ_certificate_request.py\", line 114, in <module>\r\n _ansiballz_main()\r\n File \"/home/scampos/.ansible/tmp/ansible-tmp-1595255035.770431-964964-95331819209089/AnsiballZ_certificate_request.py\", line 106, in _ansiballz_main\r\n invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)\r\n File \"/home/scampos/.ansible/tmp/ansible-tmp-1595255035.770431-964964-95331819209089/AnsiballZ_certificate_request.py\", line 49, in invoke_module\r\n imp.load_module('__main__', mod, module, MOD_DESC)\r\n File \"/usr/lib64/python3.6/imp.py\", line 235, in load_module\r\n return load_source(name, filename, file)\r\n File \"/usr/lib64/python3.6/imp.py\", line 170, in load_source\r\n module = _exec(spec, sys.modules[name])\r\n File \"<frozen importlib._bootstrap>\", line 618, in _exec\r\n File \"<frozen importlib._bootstrap_external>\", line 678, in exec_module\r\n File \"<frozen importlib._bootstrap>\", line 219, in _call_with_frames_removed\r\n File \"/tmp/ansible_certificate_request_payload_l4jc2y4h/__main__.py\", line 381, in <module>\r\n File \"/tmp/ansible_certificate_request_payload_l4jc2y4h/__main__.py\", line 377, in main\r\n File \"/tmp/ansible_certificate_request_payload_l4jc2y4h/__main__.py\", line 372, in run\r\n File \"/tmp/ansible_certificate_request_payload_l4jc2y4h/ansible_certificate_request_payload.zip/ansible/module_utils/certificate/providers/base.py\", line 612, in run\r\n File \"/tmp/ansible_certificate_request_payload_l4jc2y4h/ansible_certificate_request_payload.zip/ansible/module_utils/certificate/providers/certmonger.py\", line 149, in cert_needs_update\r\n File \"/tmp/ansible_certificate_request_payload_l4jc2y4h/ansible_certificate_request_payload.zip/ansible/module_utils/certificate/providers/base.py\", line 562, in cert_needs_update\r\n File \"/tmp/ansible_certificate_request_payload_l4jc2y4h/ansible_certificate_request_payload.zip/ansible/module_utils/certificate/providers/base.py\", line 519, in csr\r\n File \"/tmp/ansible_certificate_request_payload_l4jc2y4h/ansible_certificate_request_payload.zip/ansible/module_utils/certificate/providers/base.py\", line 186, in load_from_params\r\n File \"/tmp/ansible_certificate_request_payload_l4jc2y4h/ansible_certificate_request_payload.zip/ansible/module_utils/certificate/providers/base.py\", line 186, in <listcomp>\r\nAttributeError: module 'ansible.module_utils.six' has no attribute 'ensure_text'\r\n",
"msg": "MODULE FAILURE\nSee stdout/stderr for the exact error",
"rc": 1
}
failed: [/cache/CentOS-7-x86_64-GenericCloud-1907.qcow2c] (item={'name': 'mycert', 'dns': 'www.example.com', 'ca': 'self-sign'}) => {"ansible_loop_var": "item", "changed": false, "item": {"ca": "self-sign", "dns": "www.example.com", "name": "mycert"}, "module_stderr": "Shared connection to 127.0.0.3 closed.\r\n", "module_stdout": "/etc/profile.d/lang.sh: line 19: warning: setlocale: LC_CTYPE: cannot change locale (C.UTF-8)\r\nTraceback (most recent call last):\r\n File \"/root/.ansible/tmp/ansible-tmp-1591297080.5637057-77443-222172432255694/AnsiballZ_certificate_request.py\", line 102, in <module>\r\n _ansiballz_main()\r\n File \"/root/.ansible/tmp/ansible-tmp-1591297080.5637057-77443-222172432255694/AnsiballZ_certificate_request.py\", line 94, in _ansiballz_main\r\n invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)\r\n File \"/root/.ansible/tmp/ansible-tmp-1591297080.5637057-77443-222172432255694/AnsiballZ_certificate_request.py\", line 40, in invoke_module\r\n runpy.run_module(mod_name='ansible.modules.certificate_request', init_globals=None, run_name='__main__', alter_sys=True)\r\n File \"/usr/lib64/python2.7/runpy.py\", line 176, in run_module\r\n fname, loader, pkg_name)\r\n File \"/usr/lib64/python2.7/runpy.py\", line 82, in _run_module_code\r\n mod_name, mod_fname, mod_loader, pkg_name)\r\n File \"/usr/lib64/python2.7/runpy.py\", line 72, in _run_code\r\n exec code in run_globals\r\n File \"/tmp/ansible_certificate_request_payload_L5haZi/ansible_certificate_request_payload.zip/ansible/modules/certificate_request.py\", line 227, in <module>\r\n File \"/tmp/ansible_certificate_request_payload_L5haZi/ansible_certificate_request_payload.zip/ansible/module_utils/certificate/providers/__init__.py\", line 1, in <module>\r\n File \"/tmp/ansible_certificate_request_payload_L5haZi/ansible_certificate_request_payload.zip/ansible/module_utils/certificate/providers/certmonger.py\", line 3, in <module>\r\n File \"/tmp/ansible_certificate_request_payload_L5haZi/ansible_certificate_request_payload.zip/ansible/module_utils/certificate/providers/base.py\", line 112, in <module>\r\n File \"/tmp/ansible_certificate_request_payload_L5haZi/ansible_certificate_request_payload.zip/ansible/module_utils/certificate/providers/base.py\", line 130, in CertificateProxy\r\nAttributeError: type object 'ExtendedKeyUsageOID' has no attribute 'ANY_EXTENDED_KEY_USAGE'\r\n", "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error", "rc": 1}
I've been debugging the RHEL 7 failures in linux-system-roles/cockpit#39 , and scratching my head over why RHEL 7's curl/OpenSSL don't accept lsr.certificate self-signed certificates. Turns out the reason is that even when the request playbook variable specifies ca: self-sign
, the actually generated certificate is for the "local" CA:
Request ID '20211020094829':
status: MONITORING
stuck: no
key pair storage: type=FILE,location='/etc/pki/tls/private/monger-cockpit.key'
certificate: type=FILE,location='/etc/pki/tls/certs/monger-cockpit.crt'
CA: local
So if you try to use the certificate as its own CA (as you would with a self-signed one), at least on RHEL/CentOS 7 this fails:
# openssl s_client -CAfile /etc/pki/tls/certs/monger-cockpit.crt -verify 1 -verify_return_error -connect localhost:9090 </dev/null
verify depth is 1
CONNECTED(00000003)
depth=0 CN = localhost
verify error:num=20:unable to get local issuer certificate
139932372125584:error:14090086:SSL routines:ssl3_get_server_certificate:certificate verify failed:s3_clnt.c:1264:
[...]
For some utterly strange reason it seems to work on Fedora or RHEL 8 -- maybe certmonger creates the "local" CA lazily with the first request, and re-uses the same value for both the CA and the requested certificate? (I did not investigate this deeply).
After some digging it turns out that this is some explicit code, from the original commit f33e8e6 by @seocam :
if ca == "self-sign":
ca = "local"
@seocam, do you still remember why you did this? It seems to me that the intended thing would be to set ca = 'SelfSign'
?
FTR: I tried that locally, and it still does not work, but at least one step further.. filed as #99
When not waiting for a certificate we cannot rely on Ansible to update user and group because the file won't exist.
Instead we should create a script that will run chown
and pass this script to certmonger execute just after the certificate is issued/renewed.
The certmonger provider supports owner/group for the files.
I've tried to get a certificate for cockpit. https://100things.wzzrd.com/2021/06/10/Proper-SSL-certs-in-cockpit.html suggests using "chmod g+r" for the certificates. It might be useful to support that.
I could change the owner of my certificate to cockpit-ws, but would that be a good idea? I'm unsure.
certificate_wait is listed as a top level parameter - does it apply to all requests in the certificate_requests
list? The README.md should clarify this.
certificate_requests:
- name: /tmp/mycertTC20
dns: www.example.com
ca: self-sign
provider: certmonger
ansible-playbook tests/tests_provider_cert.yml
ls -ll /tmp/mycertTC20.crt
ls: cannot access '/tmp/mycertTC20.crt': No such file or directory
ls -ll /tmp/mycertTC20.key
ls: cannot access '/tmp/mycertTC20.key': No such file or directory
So far the tests have been executed only on Debian 10. We need to test and fix what's needs to ensure it also runs on Debian 9.
Running any of tests/tests_*.yml
more then once keeps returning changed=1
in CentOS/RedHat 7
The expected result is that after the first run the next executions would have changed=0
Reproducible by:
ansible-playbook --become -i <host_ip>, tests/tests_basic_self_signed.ym
Recap for first run:
PLAY RECAP ***********************************************************************************************
192.168.124.189 : ok=28 changed=5 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Recap for second (or third...) run:
PLAY RECAP ***********************************************************************************************
192.168.124.189 : ok=28 changed=5 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
IPA supports multiple Cert Profiles out of the box and more can be added for custom requirements. The getcert request -T option should support this.
Request that the role be updated to expose a new parameter profile
that is passed as an argument to getcert request -T
amongst other arguments.
The certificate role is not idempotent using Debian 12 on both the controller and managed node.
For details, see discussion after #45 (comment)
As part of the conscious language project, the master branch is to be renamed to the main branch.
Here are the instructions.
If you use the gh cli (highly recommended) you can use this to check which repos need to be updated:
gh repo list linux-system-roles -L 100 --json name,defaultBranchRef --source | \
jq --raw-output '.[] | select(.defaultBranchRef.name == "master") | .name'
Thanks.
Currently we are using fail_msg to print out the actual values we are asserting.
It would be good to check if running ansible in more verbose levels wouldn't show the same content. If that's the case we could remove those lines.
When key_size is set to negative value,
It sets to default one [2048]
setup_ipa.yml uses the hostname
module: https://github.com/linux-system-roles/certificate/blob/master/tests/tasks/setup_ipa.yml#L34
The module requires the hostname
command. This is not installed on all platforms. The test should install the package providing the command. This is the cause of the rhel-x
test failures.
See: #20 (comment)
When non-existent UID and GID is set for
owner:
group:
It should fail to look up for that instead of creating certificate and key.
Our integration tests are currently using openssl to extract certificate data that will be used later in the assertions. Since OpenSSL displays principal SAN as "unknown" we can't use that in the assertions.
We need to find a way to verify that the principal was properly specified in the certificate.
On versions prior to 0.79 certmonger doesn't support updating key size when updating existing certs. Because of that we should fail instead of just ignoring the users input.
As part of linux-system-roles/cockpit#39 I am debugging why ca: self-signed
certificates don't work properly on RHEL/CentOS 7. The first hurdle is issue #98, but that can be worked around easily. But then, these certificates are not accepted as CA. I created it with
- include_role:
name: linux-system-roles.certificate
vars:
certificate_requests:
- name: monger-cockpit
dns: ['localhost', 'www.example.com']
# "self-sign" does not work: https://github.com/linux-system-roles/certificate/issues/98
ca: SelfSign
group: cockpit-ws
This generates a certificate with these properties:
# openssl x509 -in /etc/pki/tls/certs/monger-cockpit.crt -text
X509v3 extensions:
X509v3 Key Usage:
Digital Signature, Key Encipherment
X509v3 Subject Alternative Name:
DNS:localhost, DNS:www.example.com
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
X509v3 Basic Constraints: critical
CA:FALSE
But curl/OpenSSL do not accept this as CA:
# openssl s_server -cert /etc/pki/tls/certs/monger-cockpit.crt -key /etc/pki/tls/private/monger-cockpit.key
# openssl s_client -CAfile /etc/pki/tls/certs/monger-cockpit.crt -verify 1 -verify_return_error -connect localhost:4433 </dev/null
The latter says
verify depth is 1
CONNECTED(00000003)
depth=0 CN = localhost
verify error:num=20:unable to get local issuer certificate
140342795151248:error:14090086:SSL routines:ssl3_get_server_certificate:certificate verify failed:s3_clnt.c:1264:
and the former (server end) logs
ERROR
139809968650128:error:14094418:SSL routines:ssl3_read_bytes:tlsv1 alert unknown ca:s3_pkt.c:1493:SSL alert number 48
shutting down SSL
CONNECTION CLOSED
The same happens with curl:
port 4433 (#0)
* Trying ::1...
* Connected to localhost (::1) port 4433 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* CAfile: /etc/pki/tls/certs/monger-cockpit.crt
CApath: none
* Server certificate:
* subject: CN=localhost
* start date: Oct 20 12:00:32 2021 GMT
* expire date: Oct 20 12:00:32 2022 GMT
* common name: localhost
* issuer: CN=localhost
* NSS error -8156 (SEC_ERROR_CA_CERT_INVALID)
* Issuer certificate is invalid.
* Closing connection 0
curl: (60) Issuer certificate is invalid.
At first I thought this would be due to a too restrictive "Key Usage". However, for some reason this works on Fedora/RHEL 8, even though the generated KU/EKU fields are the same. But OpenSSL and curl accept the .crt as CA with no problem.
If I manually request a certificate with the default properties:
# getcert request -c SelfSign -f /etc/pki/tls/certs/my.crt -k /etc/pki/tls/private/my.key -D localhost
it has different KU/EKU:
X509v3 Subject Alternative Name:
DNS:rhel-7-9-127-0-0-2-2201
X509v3 Extended Key Usage:
TLS Web Server Authentication
X509v3 Basic Constraints: critical
CA:FALSE
and I can use the same server/client commands (with the different cert path), and it works a little better:
# openssl s_server -cert /etc/pki/tls/certs/my.crt -key /etc/pki/tls/private/my.key
# openssl s_client -CAfile /etc/pki/tls/certs/my.crt -verify 1 -verify_return_error -connect localhost:4433 </dev/null
verify depth is 1
CONNECTED(00000003)
depth=0 CN = rhel-7-9-127-0-0-2-2201
verify return:1
---
Certificate chain
0 s:/CN=rhel-7-9-127-0-0-2-2201
i:/CN=rhel-7-9-127-0-0-2-2201
However, curl
is still unhappy and rejects it. I tried to generate it with more usage types like -u digitalSignature -u dataEncipherment -u keyAgreement -ukeyCertSign
, but that doesn't seem to help.
I did not track this down further so far, as it's probably moot? Supposedly l-s-r won't change much any more in RHEL 7, I just want to document this a little for referring from workarounds.
I get this running tests_basic_ipa.yml
ImportError: cannot import name 'IPA_MODULES' from 'ipaserver.install.installutils' (/usr/lib/python3.8/site-packages/ipaserver/install/installutils.py)^M
I think this has been fixed in ansible-freeipa v0.2.0 - I think the tests needs to install v0.2.0 at https://github.com/linux-system-roles/certificate/blob/master/tests/tasks/setup_ipa.yml#L15
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.