Skip to content

Commit

Permalink
Add KEYCLOAK to the laboratory stack
Browse files Browse the repository at this point in the history
Keycloak console is using secure secure cookies to manage the user
session and we therefore add SSL termination to HAProxy, offering
to generate a self-signed certificate if no configuration is provided.
  • Loading branch information
foretspaisibles committed Sep 15, 2024
1 parent 86cd552 commit 4a44beb
Show file tree
Hide file tree
Showing 5 changed files with 138 additions and 17 deletions.
33 changes: 31 additions & 2 deletions docker/compose/cid.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,18 @@
#
# cid_project (local):
# The project name to use when forming volume names.

version: '3'
#
# cid_http_port (80):
# The port to bind the HTTP listener to.
#
# cid_https_port (443):
# The port to bind the HTTPS listener to.
#
# cid_hostname (localhost):
# The configured hostname for the system.
#
# cid_keycloak_password (Administrator):
# The administrator password for Keycloak.

services:
reverseproxy:
Expand All @@ -32,6 +42,22 @@ services:
ports:
- "127.0.0.1:${cid_http_port:-80}:80"
- "127.0.0.1:${cid_https_port:-443}:443"
volumes:
- cid-ssl:/etc/ssl/private

keycloak:
image: quay.io/keycloak/keycloak:25.0.4
environment:
KEYCLOAK_ADMIN: 'Administrator'
KEYCLOAK_ADMIN_PASSWORD: ${cid_keycloak_password:-Administrator}
KC_HTTP_RELATIVE_PATH: '/authorization'
KC_PROXY_HEADERS: 'xforwarded'
KC_HTTP_ENABLED: 'true'
KC_METRICS_ENABLED: 'true'
KC_HEALTH_ENABLED: 'true'
command: start-dev
networks:
- service

gitserver:
image: cid/gitserver:${cid_image_tag:-latest}
Expand All @@ -58,6 +84,9 @@ networks:
service:

volumes:
cid-ssl:
name: cid-${cid_project:-local}-ssl
external: true
cid-trac:
name: cid-${cid_project:-local}-trac
external: true
Expand Down
7 changes: 7 additions & 0 deletions docker/image/linux/users.conf
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@
# you should have received as part of this distribution. The terms
# are also available at https://opensource.org/licenses/MIT

[haproxy]
comment = "HA Reverse Proxy"
homedir = /var/lib/haproxy
createhome = yes
system = yes
shell = /usr/sbin/nologin

[cid]
comment = "Continuous Integration and Deployment Suite"
homedir = /home/cid
Expand Down
23 changes: 20 additions & 3 deletions docker/image/reverseproxy/haproxy.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -53,21 +53,38 @@ defaults
errorfile 504 /etc/haproxy/errors/504.http

frontend http_in
mode http
bind *:80
acl is_for_trac path_beg /trac
bind 0.0.0.0:443 ssl crt /etc/ssl/private/localhost.pem
http-request redirect scheme https unless { ssl_fc }
http-request set-header X-Forwarded-Proto https if { ssl_fc }
http-request set-header X-Forwarded-Proto http if !{ ssl_fc }
acl is_for_trac path -m beg /trac/
acl is_for_trac path -m str /trac
acl is_for_keycloak path -m beg /authorization/
acl is_for_keycloak path -m str /authorization
acl is_for_webserver hdr_beg(host) -i www.
use_backend trac_server if is_for_trac
use_backend trac_server if is_for_webserver
use_backend trac_server if is_for_trac
use_backend keycloak_server if is_for_keycloak
default_backend no_server

backend trac_server
balance roundrobin
cookie SERVERID insert
option httpchk HEAD /server-status HTTP/1.0
option httpclose
option forwardfor
server trac trac:80 check

backend keycloak_server
balance roundrobin
option httpchk
option httpclose
option forwardfor
http-check connect port 9000
http-check send meth GET uri /authorization/health/ready
server keycloak keycloak:8080 check

backend no_server
http-request deny deny_status 400

Expand Down
30 changes: 18 additions & 12 deletions libexec/lisp/operation.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,6 @@
(#:docker #:org.melusina.cid/docker)
(#:cid #:org.melusina.cid))
(:export
#:lint
#+quicklisp
#:reload
#:build

;; Project
#:*project*
#:project
Expand All @@ -42,6 +37,7 @@
#:update-project
#:start-project
#:stop-project
#:restart-project
#:find-project
#:delete-project
#:project-configuration
Expand Down Expand Up @@ -208,6 +204,7 @@
(append
(when (service-enabled-p :trac project)
(list
(cons (make-volume "ssl" project) #p"/etc/ssl/private")
(cons (make-volume "trac" project) #p"/var/trac")
(cons (make-volume "www" project) #p"/var/www")
(cons (make-volume "git" project) #p"/var/git")))
Expand All @@ -225,13 +222,18 @@

(defmethod initialize-instance :after ((instance project) &rest initargs &key &allow-other-keys)
(declare (ignore initargs))
(with-slots (name pathname volumes) instance
(setf volumes
(loop :for system :in '("trac" "git" "www" "jenkins")
:collect (docker:make-volume
:name (concatenate 'string "cid-" name "-" system))))
(setf pathname
(cid:user-data-relative-pathname (concatenate 'string name "/")))))
(macrolet ((initialize-slot-from-configuration-file (slot-name designator)
`(unless (slot-value instance ,slot-name)
(setf (slot-value instance ,slot-name)
(project-configuration ,designator instance)))))
(with-slots (name pathname volumes http-port https-port ssh-port) instance
(setf volumes
(loop :for system :in '("ssl" "trac" "git" "www" "jenkins")
:collect (docker:make-volume
:name (concatenate 'string "cid-" name "-" system))))
(setf pathname
(cid:user-data-relative-pathname (concatenate 'string name "/")))
(initialize-slot-from-configuration-file 'hostname '(:project :hostname)))))

(defun make-project (&rest initargs &key name status hostname http-port https-port ssh-port docker-compose tag)
(declare (ignore name hostname http-port https-port ssh-port status docker-compose tag))
Expand Down Expand Up @@ -372,6 +374,10 @@
:output t
:error-output t)))

(defun restart-project (&optional (project *project*))
(stop-project project)
(start-project project))

(defun delete-project (&optional (project *project*))
(with-project-environment project
(uiop:run-program
Expand Down
62 changes: 62 additions & 0 deletions support/cid_configure.sh
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
: ${gnupgdir:=/home/cid/.gnupg}
: ${sshdir:=/home/cid/.ssh}
: ${wwwdir:=/var/www}
: ${ssldir:=/etc/ssl}

. "${subrdir}/stdlib.sh"
. "${subrdir}/config.sh"
Expand Down Expand Up @@ -89,6 +90,66 @@ configure_ssh()
fi
}

# configure_ssl
# Create a self-signed certificate.

configure_ssl()
{
if [ -d "${configdir}/ssl" ]; then
(
set -e
cd "${config_dir}/ssl"
find . | cpio -dump --owner 'cid:cid' "${ssldir}"
)
else
generate_self_signed_certificate
fi

find "${ssldir}" -type f -exec chmod go= '{}' ';'
find "${ssldir}" -type f -exec chown haproxy:haproxy '{}' ';'
}

generate_self_signed_certificate()
(
local hostname
hostname="$(configure_config project.hostname)"

field()
{
printf '/%s=%s' "$@"
}

subject()
{
field 'C' 'FR'
field 'ST' 'Isle-de-France'
field 'L' 'Paris'
field 'O' 'Melusina'
field 'OU' 'Melusina Development'
field 'CN' 'Melusina Development Platform'
}

openssl genrsa -out "${ssldir}/private/${hostname}.key" 2048
openssl req\
-new\
-subj "$(subject)"\
-addext "subjectAltName = DNS:${hostname}"\
-key "${ssldir}/private/${hostname}.key"\
-out "${ssldir}/private/${hostname}.csr"
openssl x509\
-req -days 365\
-in "${ssldir}/private/${hostname}.csr"\
-signkey "${ssldir}/private/${hostname}.key"\
-out "${ssldir}/private/${hostname}.crt"
cat\
"${ssldir}/private/${hostname}.key"\
"${ssldir}/private/${hostname}.crt"\
> "${ssldir}/private/${hostname}.pem"
cp\
"${ssldir}/private/${hostname}.pem"\
"${ssldir}/private/localhost.pem"
)

configure_batch()
{
local service
Expand All @@ -103,6 +164,7 @@ configure_batch()

config_setup
configure_assert
configure_ssl
configure_batch

# End of file `cid_configure.sh'

0 comments on commit 4a44beb

Please sign in to comment.