[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[bug#63375] [cuirass v3] doc: Document authentication.
From: |
Maxim Cournoyer |
Subject: |
[bug#63375] [cuirass v3] doc: Document authentication. |
Date: |
Thu, 11 May 2023 00:34:52 -0400 |
* etc/new-client-cert.scm: Add script.
* doc/cuirass.texi (Authentication): Document it.
* Makefile.am (noinst_SCRIPTS): Register it.
---
Makefile.am | 2 +-
doc/cuirass.texi | 86 ++++++++++++++++++++++++++++
etc/new-client-cert.scm | 121 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 208 insertions(+), 1 deletion(-)
create mode 100755 etc/new-client-cert.scm
diff --git a/Makefile.am b/Makefile.am
index a40a76d..62b0860 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -25,7 +25,7 @@
bin_SCRIPTS = \
bin/cuirass
-noinst_SCRIPTS = pre-inst-env
+noinst_SCRIPTS = pre-inst-env etc/new-client-cert.scm
guilesitedir = $(datarootdir)/guile/site/@GUILE_EFFECTIVE_VERSION@
guileobjectdir = $(libdir)/guile/@GUILE_EFFECTIVE_VERSION@/site-ccache
diff --git a/doc/cuirass.texi b/doc/cuirass.texi
index db46a33..728ca7f 100644
--- a/doc/cuirass.texi
+++ b/doc/cuirass.texi
@@ -13,6 +13,7 @@ Copyright @copyright{} 2016, 2017 Mathieu Lirzin@*
Copyright @copyright{} 2017, 2020, 2021 Mathieu Othacehe@*
Copyright @copyright{} 2018, 2021 Ludovic Courtès@*
Copyright @copyright{} 2018 Clément Lassieur
+Copyright @copyright{} 2023 Maxim Cournoyer@*
@quotation
Permission is granted to copy, distribute and/or modify this document
@@ -57,6 +58,7 @@ Documentation License''.
* Parameters:: Cuirass parameters.
* Build modes:: Build modes.
* Invocation:: How to run Cuirass.
+* Authentication:: Configuring TLS authentication.
* Web API:: Description of the Web API.
* Database:: About the database schema.
@@ -711,6 +713,90 @@ Display the actual version of @code{cuirass}.
Display an help message that summarize all the options provided.
@end table
+@c *********************************************************************
+@node Authentication
+@chapter Authentication
+@cindex authentication
+
+Cuirass does not provide its own authentication mechanism; by default,
+any user can do anything via its web interface. To restrict this to
+only authorized users, one approach is to proxy the Cuirass web site via
+a web server such as Nginx and configure the web server to require
+client certificate verification for pages under the @samp{/admin}
+prefix. The following minimal Nginx configuration can be used to
+accomplish this on a Guix System:
+
+@lisp
+(service nginx-service-type
+ (nginx-configuration
+ (server-blocks
+ (list
+ ;; TLS is required for authentication; serve the site via
+ ;; HTTPS only.
+ (nginx-server-configuration
+ (listen '("80"))
+ (raw-content
+ (list "return 308 https://$host$request_uri;")))
+
+ (nginx-server-configuration
+ (listen '("443 ssl"))
+ (server-name '("ci.your-host.org"))
+ (ssl-certificate "/etc/certs/ci.your-host.org.crt")
+ (ssl-certificate-key "/etc/certs/ci.your-host.org.key")
+ (locations
+ (list
+ ;; Proxy the whole Cuirass web site...
+ (nginx-location-configuration
+ (uri "/")
+ (body (list "proxy_pass http://localhost:8081;")))
+ ;; ... but require authentication for the admin pages.
+ (nginx-location-configuration
+ (uri "~ ^/admin")
+ (body
+ (list "if ($ssl_client_verify != SUCCESS) \
+@{ return 403; @} proxy_pass http://localhost:8081;")))))
+ (raw-content
+ ;; Register your self-generated certificate authority.
+ (list "ssl_client_certificate /etc/ssl-ca/certs/ca.crt;"
+ "ssl_verify_client optional;")))))))
+@end lisp
+
+Your host TLS certificate could have been obtained via Let's Encrypt or
+directly via the @command{openssl} command, among other means. To
+create a private certificate authority (CA) that can sign user
+certificates, a convenience script is provided. It's main requirement
+is to have the @command{guix} command available. It can be invoked
+like:
+
+@example
+sudo -E ./etc/new-client-cert.scm --generate-ca
+@end example
+
+It should generate the @file{/etc/ssl-ca/private/ca.key} private key as
+well as the @file{/etc/ssl-ca/certs/ca.crt} certificate authority as
+used in the Nginx configuration above.
+
+To issue a new user certificate, run the same script from your home
+directory with:
+
+@example
+sudo -E ./etc/new-client-cert.scm
+@end example
+
+You will be asked to input the password for the CA private key, if any,
+and again for your new certificate; save it carefully. The script
+requires to run as root to have access to the private certificate
+authority key; it outputs the new user certificate files to the current
+working directory.
+
+After your new CA-signed user certificate is generated, it needs to be
+registered with your web browser. To do so using GNU IceCat, for
+example, you can navigate to @samp{Parameters -> Security -> Show
+certificates} and then click the @samp{Import...} button and select your
+@file{.pk12} personal certificate file. The web interface of Cuirass
+should now only allow authenticated users to perform administrative
+tasks.
+
@c *********************************************************************
@node Web API
@chapter Web API
diff --git a/etc/new-client-cert.scm b/etc/new-client-cert.scm
new file mode 100755
index 0000000..4fac772
--- /dev/null
+++ b/etc/new-client-cert.scm
@@ -0,0 +1,121 @@
+#!/usr/bin/env -S guix shell guile openssl -- guile \\
+--no-auto-compile -e main -s
+!#
+;;;; cuirass.scm -- Cuirass public interface.
+;;; Copyright © 2023 Ricardo Wurmus <rekado@elephly.net>
+;;; Copyright © 2023 Maxim Cournoyer <maxim.cournoyer@gmail.com>
+;;;
+;;; This file is part of Cuirass.
+;;;
+;;; Cuirass 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, either version 3 of the License, or
+;;; (at your option) any later version.
+;;;
+;;; Cuirass 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 Cuirass. If not, see <http://www.gnu.org/licenses/>.
+
+(use-modules (ice-9 format)
+ (ice-9 match)
+ (guix build utils))
+
+(define %user (or (getenv "SUDO_USER")
+ (getenv "USER")))
+
+(define %user-id (passwd:uid (getpwnam %user)))
+
+(define %group-id (passwd:gid (getpwnam %user)))
+
+(define %CA-directory
+ "/etc/ssl-ca")
+
+(define subject-template
+ "/C=DE/ST=Berlin/L=Berlin/O=GNU Guix/OU=Cuirass/CN=~a")
+
+(define CA-key
+ (string-append %CA-directory "/private/ca.key"))
+(define CA-cert
+ (string-append %CA-directory "/certs/ca.crt"))
+
+(define* (output who file)
+ (string-append (getcwd) "/" who file))
+
+(define (key-file who)
+ "Return the absolute file name of the key file for WHO."
+ (output who ".key"))
+
+(define (csr-file who)
+ "Return the absolute file name of the CSR file for WHO."
+ (output who ".csr"))
+
+(define (client-cert-file who)
+ "Return the absolute file name of the client certificate file for
+WHO."
+ (output who ".crt"))
+
+(define (exported-cert-file who)
+ "Return the absolute file name of the pkcs12 client certificate file
+for WHO. This is the file that users should import into their
+browsers."
+ (output who ".p12"))
+
+(define (generate-ca!)
+ "Generate a private certificate authority (CA) valid for 10 years."
+ (mkdir-p (dirname CA-key))
+ (mkdir-p (dirname CA-cert))
+ (invoke "openssl" "req" "-newkey" "rsa" "-x509" "-days" "3650"
+ "-noenc" ;no password
+ "-subj" (format #false "~@?" subject-template "Cuirass CA")
+ "-keyout" CA-key "-out" CA-cert))
+
+(define (generate-csr! who)
+ "Generate a new certificate signing request and key for WHO."
+ (let ((key (key-file who))
+ (csr (csr-file who)))
+ (invoke "openssl" "req" "-newkey" "rsa"
+ "-noenc" ;no password
+ "-subj" (format #false "~@?" subject-template who)
+ "-keyout" key
+ "-out" csr)
+ (chown key %user-id %group-id)
+ (chown csr %user-id %group-id)))
+
+(define* (generate-client-certificate! who #:key (expiry 365))
+ "Generate a client certificate for WHO."
+ (let ((cert (client-cert-file who)))
+ (invoke "openssl" "x509" "-req"
+ "-in" (csr-file who)
+ "-CA" CA-cert
+ "-CAkey" CA-key
+ "-out" cert
+ "-days" (number->string expiry))
+ (chown cert %user-id %group-id)))
+
+(define (export-p12! who)
+ (let ((key (key-file who))
+ (exported-cert (exported-cert-file who)))
+ (invoke "openssl" "pkcs12" "-export"
+ "-in" (client-cert-file who)
+ "-inkey" key
+ "-out" exported-cert)
+ (chown key %user-id %group-id)
+ (chown exported-cert %user-id %group-id)))
+
+(define (main args)
+ (match (command-line)
+ ((script)
+ (set-program-arguments (list script %user))
+ (apply main args))
+ ((script "--generate-ca")
+ (generate-ca!))
+ ((script who)
+ (generate-csr! who)
+ (generate-client-certificate! who)
+ (export-p12! who))
+ ((script . rest)
+ (format (current-error-port) "usage: ~a [--generate-ca|name]~%" script))))
base-commit: cf4e3e4ac4a9c8d6f0d82b0a173826f15bbca7f3
--
2.39.2