[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
01/01: hydra: Add initial configuration of berlin.
From: |
Ricardo Wurmus |
Subject: |
01/01: hydra: Add initial configuration of berlin. |
Date: |
Thu, 20 Jul 2017 17:43:43 -0400 (EDT) |
rekado pushed a commit to branch master
in repository maintenance.
commit 7d1f97258b9071a227a8c4e191f74b59dae325ef
Author: Ricardo Wurmus <address@hidden>
Date: Thu Jul 20 23:42:37 2017 +0200
hydra: Add initial configuration of berlin.
* hydra/berlin.scm: New file.
* hydra/nginx/berlin.conf: New file.
---
hydra/berlin.scm | 284 ++++++++++++++++++++++++++++++++++++++++++++++++
hydra/nginx/berlin.conf | 145 ++++++++++++++++++++++++
2 files changed, 429 insertions(+)
diff --git a/hydra/berlin.scm b/hydra/berlin.scm
new file mode 100644
index 0000000..44b4796
--- /dev/null
+++ b/hydra/berlin.scm
@@ -0,0 +1,284 @@
+;; OS configuration for "berlin", the frontend of the compile farm
+;; hosted at the MDC.
+
+(use-modules (gnu) (guix) (sysadmin people))
+(use-service-modules base networking admin mcron shepherd ssh web cuirass)
+(use-package-modules admin emacs linux ssh tls vim package-management web wget
ci)
+
+(define (maintenance-file name)
+ (local-file (string-append "/root/maintenance/hydra/" name)))
+
+(define %sysadmins
+ ;; The sysadmins.
+ (list (sysadmin (name "ludo")
+ (full-name "Ludovic Courtès")
+ (lsh-public-key (maintenance-file "keys/lsh/ludo.pub")))
+ (sysadmin (name "rekado")
+ (full-name "Ricardo Wurmus")
+ (lsh-public-key (maintenance-file "keys/lsh/rekado.pub")))
+ (sysadmin (name "andreas")
+ (full-name "Andreas Enge")
+ (lsh-public-key (maintenance-file "keys/lsh/andreas.pub")))
+ ;; (sysadmin (name "bi-admin")
+ ;; (full-name "MDC admin")
+ ;; (lsh-public-key (maintenance-file
"keys/lsh/bi-admin.pub")))
+ ))
+
+
+(define %gc-job
+ ;; The garbage collection mcron job, once per day.
+ #~(job '(next-hour '(4))
+ (string-append #$guix "/bin/guix gc -F80G")))
+
+(define %certbot-job
+ ;; Attempt to renew the Let's Encrypt certificate twice a week.
+ #~(job (lambda (now)
+ (next-day-from (next-hour-from now '(3))
+ '(2 5)))
+ (string-append #$certbot "/bin/certbot renew")))
+
+(define %guix-daemon-config
+ (guix-configuration
+ ;; Disable substitutes altogether.
+ (use-substitutes? #f)
+ (substitute-urls '())
+ (authorized-keys '())
+ (max-silent-time 7200)
+ (timeout (* 4 max-silent-time))
+
+ (extra-options '("--max-jobs=5" "--cores=4" ;we have 8 cores
+ "--cache-failures"
+ "--gc-keep-outputs" "--gc-keep-derivations"))))
+
+(define start-firewall
+ ;; Rules to throttle malicious SSH connection attempts. This will allow at
+ ;; most 3 connections per minute from any host, and will block the host for
+ ;; another minute if this rate is exceeded. Taken from
+ ;; <http://www.la-samhna.de/library/brutessh.html#3>.
+ #~(let ((iptables
+ (lambda (str)
+ (zero? (apply system*
+ #$(file-append iptables
+ "/sbin/iptables")
+ (string-tokenize str))))))
+ (format #t "Installing iptables SSH rules...~%")
+ (and (iptables "-A INPUT -p tcp --dport 22 -m state \
+ --state NEW -m recent --set --name SSH -j ACCEPT")
+ (iptables "-A INPUT -p tcp --dport 22 -m recent \
+ --update --seconds 60 --hitcount 4 --rttl \
+ --name SSH -j LOG --log-prefix SSH_brute_force")
+ (iptables "-A INPUT -p tcp --dport 22 -m recent \
+ --update --seconds 60 --hitcount 4 --rttl --name SSH -j DROP"))))
+
+(define firewall-service
+ ;; The "firewall". Make it a Shepherd service because as an activation
+ ;; script it might run too early, before the Netfilter modules can be
+ ;; loaded for some reason.
+ (simple-service 'firewall shepherd-root-service-type
+ (list (shepherd-service
+ (provision '(firewall))
+ (requirement '())
+ (start #~(lambda ()
+ #$start-firewall))
+ (respawn? #f)))))
+
+
+;;;
+;;; NGINX.
+;;;
+
+(define %nginx-config
+ ;; Our nginx configuration directory. It expects 'guix publish' to be
+ ;; running on port 3000.
+ (computed-file "nginx-config"
+ (with-imported-modules '((guix build utils))
+ #~(begin
+ (use-modules (guix build utils))
+
+ (mkdir #$output)
+ (chdir #$output)
+ (symlink #$(local-file "/root/berlin-nginx.conf")
"berlin.conf")
+ (copy-file #$(local-file
+
"/root/maintenance/hydra/nginx/bayfront-locations.conf")
+ "berlin-locations.conf")
+ (substitute* "berlin-locations.conf"
+ (("@WWWROOT@")
+ #$(local-file "/root/maintenance/hydra/nginx/html"
#:recursive? #t)))))))
+
+(define %nginx-mime-types
+ ;; Provide /etc/nginx/mime.types (and a bunch of other files.)
+ (simple-service 'nginx-mime.types
+ etc-service-type
+ `(("nginx" ,(file-append nginx "/share/nginx/conf")))))
+
+(define %nginx-cache-activation
+ ;; Make sure /var/cache/nginx exists on the first run.
+ (simple-service 'nginx-/var/cache/nginx
+ activation-service-type
+ (with-imported-modules '((guix build utils))
+ #~(begin
+ (use-modules (guix build utils))
+ (mkdir-p "/var/cache/nginx")))))
+
+
+;;;
+;;; Cuirass.
+;;;
+
+(define %cuirass-specs
+ ;; Cuirass specifications to build Guix.
+ #~(list `((#:name . "guix")
+ ;; FIXME: The campus firewall blocks access to git://
+ (#:url . "https://git.savannah.gnu.org/git/guix.git")
+ (#:load-path . ".")
+
+ ;; FIXME: Currently this must be an absolute file name because
+ ;; the 'evaluate' command of Cuirass loads it with
+ ;; 'primitive-load'.
+ ;; Use our own variant of Cuirass' 'examples/gnu-system.scm'.
+ (#:file . #$(local-file
"/root/maintenance/hydra/cuirass-jobs.scm"))
+ (#:no-compile? #t) ;don't try to run ./bootstrap etc.
+
+ (#:proc . hydra-jobs)
+ (#:arguments (subset . "all"))
+ (#:branch . "master"))))
+
+
+;;;
+;;; Operating system.
+;;;
+
+(define %motd
+ ;; Message of the day! Libcaca's img2txt gives something that's not so
+ ;; great.
+ (plain-file "motd"
+ "\
+ : .
+ S: S
+ : 8 . . :8 t . . . ;
+ %888. ; : SX8@
+ t 8 % .
+ .8 8 .
+ .88 t : Welcome to berlin!
+ . t .8
+ . % . 8
+ 8 8 8
+ . X 8
+ 8 address@hidden
+
+Best practices:
+
+ 1. Store everything in guix-maintenance.git.
+ 2. Use the Git checkouts of Guix and guix-maintenance in ~root.
+ 3. Notify address@hidden when reconfiguring.
+ 4. Notify address@hidden when something goes wrong.
+
+ 5. Notify address@hidden or address@hidden when the
+ machine doesn't respond. Only Ricardo has access to the serial console
+ to reset the machine.
+
+Happy hacking!\n"))
+
+
+(operating-system
+ (host-name "berlin.guixsd.org")
+ (timezone "Europe/Berlin")
+ (locale "en_US.utf8")
+
+ ;; Allow access through the serial console at 141.80.113.141; the
+ ;; management interface can only be accessed through selected
+ ;; servers within the MDC campus network.
+ (kernel-arguments '("console=tty0"
+ "console=ttyS1,9600n8"))
+
+ ;; The SunFire X2200 M2 servers need this kernel module for their
+ ;; disk controllers.
+ (initrd (lambda (fs . args)
+ (apply base-initrd fs
+ #:extra-modules (list "sata_nv")
+ args)))
+
+ ;; Show the GRUB menu on the serial interface.
+ (bootloader (grub-configuration (device "/dev/sda")
+ (terminal-inputs '(serial))
+ (terminal-outputs '(serial))))
+
+ ;; Just a single disk, no RAID :-/
+ (file-systems (cons (file-system
+ (device "my-root")
+ (title 'label)
+ (mount-point "/")
+ (type "ext4"))
+ %base-file-systems))
+
+ ;; Local admin account for MDC maintenance.
+ (users (cons (user-account
+ (name "bi-admin")
+ (comment "Local admin")
+ (group "users")
+ (supplementary-groups '("wheel"))
+ (home-directory "/home/bi-admin"))
+ %base-user-accounts))
+
+ (packages (cons* certbot emacs wget iptables
+ jnettop lm-sensors openssh
+ %base-packages))
+
+ (services (cons*
+ (service sysadmin-service-type %sysadmins)
+
+ ;; TODO: configure the second network interface once it's
+ ;; hooked up to the switch.
+ (static-networking-service "enp6s4f0"
+ "141.80.181.40"
+ #:netmask "255.255.255.0"
+ #:gateway "141.80.181.1")
+ (lsh-service #:port-number 22)
+
+ ;; Allow login over serial console.
+ (agetty-service (agetty-configuration
+ (tty "ttyS1")
+ (baud-rate "9600")))
+
+ ;; The Web service.
+ (service guix-publish-service-type
+ (guix-publish-configuration
+ (port 3000)
+ (cache "/var/cache/guix/publish")
+ (ttl (* 45 24 3600))
+ (compression-level 9)
+ (workers 8)))
+
+ (nginx-service #:config-file
+ (file-append %nginx-config
+ "/berlin.conf"))
+ %nginx-mime-types
+ %nginx-cache-activation
+
+ (service cuirass-service-type
+ (cuirass-configuration
+ (interval (* 5 60))
+ (specifications %cuirass-specs)))
+
+ ;; Make SSH and HTTP/HTTPS available over Tor.
+ (tor-hidden-service "http"
+ '((22 "127.0.0.1:22")
+ (80 "127.0.0.1:80")
+ (443 "127.0.0.1:443")))
+ (tor-service)
+
+ ;; Cron and log rotation.
+ (service rottlog-service-type (rottlog-configuration))
+ (service mcron-service-type
+ (mcron-configuration
+ (jobs (list %gc-job %certbot-job))))
+
+ firewall-service
+
+ (modify-services %base-services
+ ;; Disable substitutes altogether.
+ (guix-service-type config => %guix-daemon-config)
+ (login-service-type
+ config => (login-configuration
+ (inherit config)
+ (motd %motd)))))))
diff --git a/hydra/nginx/berlin.conf b/hydra/nginx/berlin.conf
new file mode 100644
index 0000000..f3272e5
--- /dev/null
+++ b/hydra/nginx/berlin.conf
@@ -0,0 +1,145 @@
+# This is the nginx config file for berlin.guixsd.conf.
+
+user nginx;
+worker_processes auto;
+
+error_log /var/log/nginx/error.log error;
+pid /var/run/nginx.pid;
+
+pcre_jit on;
+
+events {
+ worker_connections 1024;
+}
+
+http {
+ include /etc/nginx/mime.types;
+ default_type application/octet-stream;
+
+ # We need to specify all these or nginx picks its own directory to
+ # store them, which doesn't work because the store is read-only.
+ client_body_temp_path /var/run/nginx/body;
+ proxy_temp_path /var/run/nginx/proxy;
+ fastcgi_temp_path /var/run/nginx/fastcgi;
+ uwsgi_temp_path /var/run/nginx/uwsgi;
+ scgi_temp_path /var/run/nginx/scgi;
+
+ access_log /var/log/nginx/access.log;
+
+ sendfile on;
+
+ # Maximum chunk size to send. Partly this is a workaround
+ # for <http://bugs.gnu.org/19939>, but also the nginx docs
+ # mention that "Without the limit, one fast connection may
+ # seize the worker process entirely."
+ # <http://nginx.org/en/docs/http/ngx_http_core_module#sendfile_max_chunk>
+ sendfile_max_chunk 1m;
+
+ keepalive_timeout 65;
+
+ # Use HTTP 1.1 to talk to the backend so we benefit from
+ # keep-alive connections and chunked transfer encoding. The
+ # latter allows us to make sure we do not cache partial downloads.
+ proxy_http_version 1.1;
+
+ # The 'inactive' parameter for caching is not very useful in our
+ # case: all that matters is that LRU sweeping happens when
+ # 'max_size' is hit.
+
+ # cache for narinfo files
+ proxy_cache_path /var/cache/nginx/narinfo
+ levels=2
+ inactive=7d # inactive keys removed after 7d
+ keys_zone=narinfo:4m # narinfo meta data: ~32K keys
+ max_size=5g; # total cache data size max
+
+ # cache for nar files
+ proxy_cache_path /var/cache/nginx/nar
+ levels=2
+ inactive=8d # inactive keys removed after 8d
+ keys_zone=nar:4m # nar cache meta data: ~32K keys
+ max_size=50g; # total cache data size max
+
+ # cache for content-addressed files
+ proxy_cache_path /var/cache/nginx/cas
+ levels=2
+ inactive=180d # inactive keys removed after 180d
+ keys_zone=cas:8m # nar cache meta data: ~64K keys
+ max_size=30g; # total cache data size max
+
+ # cache for build logs
+ proxy_cache_path /var/cache/nginx/logs
+ levels=2
+ inactive=60d # inactive keys removed after 60d
+ keys_zone=logs:8m # narinfo meta data: ~64K keys
+ max_size=4g; # total cache data size max
+
+ # cache for static data
+ proxy_cache_path /var/cache/nginx/static
+ levels=1
+ inactive=10d # inactive keys removed after 10d
+ keys_zone=static:1m # nar cache meta data: ~8K keys
+ max_size=200m; # total cache data size max
+
+ # If Hydra cannot honor these delays, then something is wrong and
+ # we'd better drop the connection and return 504.
+ proxy_connect_timeout 7s;
+ proxy_read_timeout 10s;
+ proxy_send_timeout 10s;
+
+ # Cache timeouts for a little while to avoid increasing pressure.
+ proxy_cache_valid 504 30s;
+
+ server {
+ listen 80;
+ server_name berlin.guixsd.org;
+
+ access_log /var/log/nginx/http.access.log;
+
+ proxy_set_header X-Forwarded-Host $host;
+ proxy_set_header X-Forwarded-Port $server_port;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+
+ include berlin-locations.conf;
+ }
+
+ server {
+ listen 80;
+ server_name bootstrappable.org;
+ root /home/rekado/bootstrappable.org;
+ index index.html;
+ access_log /var/log/nginx/bootstrappable.access.log;
+ location = / {
+ root /home/rekado/bootstrappable.org;
+ }
+ }
+
+ # HTTPS server.
+ server {
+ listen 443 ssl;
+ server_name berlin.guixsd.org;
+
+ ssl_certificate
/etc/letsencrypt/live/berlin.guixsd.org/fullchain.pem;
+ ssl_certificate_key
/etc/letsencrypt/live/berlin.guixsd.org/privkey.pem;
+
+ # Make sure SSL is disabled.
+ ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
+
+ # Disable weak cipher suites.
+ ssl_ciphers HIGH:!aNULL:!MD5;
+ ssl_prefer_server_ciphers on;
+
+ # Use our own DH parameters created with:
+ # openssl dhparam -out dhparams.pem 2048
+ # as suggested at <https://weakdh.org/sysadmin.html>.
+ ssl_dhparam /etc/dhparams.pem;
+
+ access_log /var/log/nginx/https.access.log;
+
+ proxy_set_header X-Forwarded-Host $host;
+ proxy_set_header X-Forwarded-Port $server_port;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+
+ include berlin-locations.conf;
+ }
+}