mirror of
				https://github.com/laurivosandi/certidude
				synced 2025-10-31 01:19:11 +00:00 
			
		
		
		
	Added diagrams and improved docs
This commit is contained in:
		
							
								
								
									
										21
									
								
								README.rst
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								README.rst
									
									
									
									
									
								
							| @@ -5,9 +5,10 @@ Introduction | ||||
| ------------ | ||||
|  | ||||
| Certidude is a novel X.509 Certificate Authority management tool | ||||
| with privilege isolation mechanism aiming to | ||||
| with privilege isolation mechanism and Kerberos authentication aiming to | ||||
| eventually support PKCS#11 and in far future WebCrypto. | ||||
|  | ||||
| .. figure:: doc/usecase-diagram.png | ||||
|  | ||||
| Features | ||||
| -------- | ||||
| @@ -106,19 +107,19 @@ Use web interface or following to sign a certificate on Certidude server: | ||||
| Production deployment | ||||
| --------------------- | ||||
|  | ||||
| Install uWSGI: | ||||
| Install ``nginx`` and ``uwsgi``: | ||||
|  | ||||
| .. code:: bash | ||||
|  | ||||
|     apt-get install nginx uwsgi uwsgi-plugin-python3 | ||||
|  | ||||
| To set up ``nginx`` and ``uwsgi`` is suggested: | ||||
| For easy setup following is reccommended: | ||||
|  | ||||
| .. code:: bash | ||||
|  | ||||
|     certidude setup production | ||||
|  | ||||
| Otherwise manually configure uUWSGI application in ``/etc/uwsgi/apps-available/certidude.ini``: | ||||
| Otherwise manually configure ``uwsgi`` application in ``/etc/uwsgi/apps-available/certidude.ini``: | ||||
|  | ||||
| .. code:: ini | ||||
|  | ||||
| @@ -136,8 +137,12 @@ Otherwise manually configure uUWSGI application in ``/etc/uwsgi/apps-available/c | ||||
|     callable = app | ||||
|     chmod-socket = 660 | ||||
|     chown-socket = certidude:www-data | ||||
|     buffer-size = 32768 | ||||
|     env = PUSH_PUBLISH=http://localhost/event/publish/%(channel)s | ||||
|     env = PUSH_SUBSCRIBE=http://localhost/event/subscribe/%(channel)s | ||||
|     env = LANG=C.UTF-8 | ||||
|     env = LC_ALL=C.UTF-8 | ||||
|     env = KRB5_KTNAME=/etc/certidude.keytab | ||||
|  | ||||
| Also enable the application: | ||||
|  | ||||
| @@ -272,11 +277,11 @@ to generate user whitelist via LDAP: | ||||
|  | ||||
| .. code:: bash | ||||
|  | ||||
|     ldapsearch -H ldap://dc1.id.stipit.com -s sub -x -LLL \ | ||||
|         -D 'cn=certidude,cn=Users,dc=id,dc=stipit,dc=com' \ | ||||
|     ldapsearch -H ldap://dc1.example.com -s sub -x -LLL \ | ||||
|         -D 'cn=certidude,cn=Users,dc=example,dc=com' \ | ||||
|         -w 'certidudepass' \ | ||||
|         -b 'ou=sso,dc=id,dc=stipit,dc=com' \ | ||||
|         '(objectClass=user)' sAMAccountName userPrincipalName givenName sn \ | ||||
|         -b 'dc=example,dc=com' \ | ||||
|         '(&(objectClass=user)(memberOf=cn=Domain Admins,cn=Users,dc=example,dc=com))' sAMAccountName userPrincipalName givenName sn \ | ||||
|     | python3 -c "import ldif3; import sys; [sys.stdout.write('%s:%s:%s:%s\n' % (a.pop('sAMAccountName')[0], a.pop('userPrincipalName')[0], a.pop('givenName')[0], a.pop('sn')[0])) for _, a in ldif3.LDIFParser(sys.stdin.buffer).parse()]" \ | ||||
|     > /run/certidude/user.whitelist | ||||
|  | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| import re | ||||
| import falcon | ||||
| import ipaddress | ||||
| import os | ||||
| import json | ||||
| import types | ||||
| @@ -23,9 +24,25 @@ def omit(**kwargs): | ||||
|  | ||||
| def authorize_admin(func): | ||||
|     def wrapped(self, req, resp, *args, **kwargs): | ||||
|         authority = kwargs.get("ca") | ||||
|  | ||||
|         # Parse remote IPv4/IPv6 address | ||||
|         remote_addr = ipaddress.ip_network(req.env["REMOTE_ADDR"]) | ||||
|  | ||||
|         # Check for administration subnet whitelist | ||||
|         print("Comparing:", authority.admin_subnets, "To:", remote_addr) | ||||
|         for subnet in authority.admin_subnets: | ||||
|             if subnet.overlaps(remote_addr): | ||||
|                 break | ||||
|         else: | ||||
|             raise falcon.HTTPForbidden("Forbidden", "Remote address %s not whitelisted" % remote_addr) | ||||
|  | ||||
|         # Check for username whitelist | ||||
|         kerberos_username, kerberos_realm = kwargs.get("user") | ||||
|         if kerberos_username not in kwargs.get("ca").admin_users: | ||||
|             raise falcon.HTTPForbidden("User %s not whitelisted" % kerberos_username) | ||||
|         if kerberos_username not in authority.admin_users: | ||||
|             raise falcon.HTTPForbidden("Forbidden", "User %s not whitelisted" % kerberos_username) | ||||
|  | ||||
|         # Retain username, TODO: Better abstraction with username, e-mail, sn, gn? | ||||
|         kwargs["user"] = kerberos_username | ||||
|         return func(self, req, resp, *args, **kwargs) | ||||
|     return wrapped | ||||
| @@ -34,7 +51,6 @@ def authorize_admin(func): | ||||
| def pop_certificate_authority(func): | ||||
|     def wrapped(self, req, resp, *args, **kwargs): | ||||
|         kwargs["ca"] = self.config.instantiate_authority(kwargs["ca"]) | ||||
|         print(func) | ||||
|         return func(self, req, resp, *args, **kwargs) | ||||
|     return wrapped | ||||
|  | ||||
| @@ -86,7 +102,6 @@ def templatize(path): | ||||
|     def wrapper(func): | ||||
|         def wrapped(instance, req, resp, *args, **kwargs): | ||||
|             assert not req.get_param("unicode") or req.get_param("unicode") == u"✓", "Unicode sanity check failed" | ||||
|             print("templatize would call", func, "with", args, kwargs) | ||||
|             r = func(instance, req, resp, *args, **kwargs) | ||||
|             r.pop("self") | ||||
|             if not resp.body: | ||||
| @@ -212,7 +227,7 @@ class RequestListResource(CertificateAuthorityBase): | ||||
|         Submit certificate signing request (CSR) in PEM format | ||||
|         """ | ||||
|         # Parse remote IPv4/IPv6 address | ||||
|         remote_addr = ipaddress.ip_address(req.env["REMOTE_ADDR"]) | ||||
|         remote_addr = ipaddress.ip_network(req.env["REMOTE_ADDR"]) | ||||
|  | ||||
|         # Check for CSR submission whitelist | ||||
|         if ca.request_subnets: | ||||
| @@ -220,7 +235,7 @@ class RequestListResource(CertificateAuthorityBase): | ||||
|                 if subnet.overlaps(remote_addr): | ||||
|                     break | ||||
|             else: | ||||
|                raise falcon.HTTPForbidden("IP address %s not whitelisted" % remote_addr) | ||||
|                raise falcon.HTTPForbidden("Forbidden", "IP address %s not whitelisted" % remote_addr) | ||||
|  | ||||
|         if req.get_header("Content-Type") != "application/pkcs10": | ||||
|             raise falcon.HTTPUnsupportedMediaType( | ||||
| @@ -308,6 +323,7 @@ class CertificateAuthorityResource(CertificateAuthorityBase): | ||||
| class IndexResource(CertificateAuthorityBase): | ||||
|     @login_required | ||||
|     @pop_certificate_authority | ||||
|     @authorize_admin | ||||
|     @templatize("index.html") | ||||
|     def on_get(self, req, resp, ca, user): | ||||
|         return locals() | ||||
|   | ||||
							
								
								
									
										
											BIN
										
									
								
								doc/usecase-diagram.dia
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								doc/usecase-diagram.dia
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								doc/usecase-diagram.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								doc/usecase-diagram.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 38 KiB | 
		Reference in New Issue
	
	Block a user