summaryrefslogtreecommitdiff
path: root/Infrastruktur/Cloud-Server.mdwn
blob: f19dc6237eb3291f5267f18cc4d070744cc554a8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
[[!meta title="Cloud-Server der Starship Factory"]]

[[!toc startlevel=2]]

# Cloud-Server

Der Cloud-Server dient zum Austausch von Dateien und Informationen zwischen den Mitgliedern der Starship Factory. Er dient primär zur Bereitstellung einer NextCloud-Instanz für diese Zweck. Neben dieser ist zusätzlich ein LDAP-Server zur Benutzerverwaltung und Authentifizierung installiert.

Der Cloud-Server wurde von Bernd Kalbfuss (aka Langweiler) eingerichtet. Er wird aktuell von den folgenden Personen administriert:

| Name            | Spitzname/Benutzername | E-Mail                    |
| --------------- | ---------------------- | ------------------------- |
| Bernd Kalbfuss  | langweiler             | langweiler@rueblitorte.de |
| Fabian Thoma    | fabianthoma            | f@bianthoma.me            |
| Cedric Spindler | zedcat                 | cedric.spindler@gmail.com |

## Hardware

Der Cloud-Server läuft auf einem HP ProLiant ML110-Server der vermutlich 5. Generation. Er besitzt eine CPU mit zwei Kernen. Die Leistungsdaten der CPU sind wie folgt:

| Merkmal       | Wert |
| ------------- | ---- |
| Product       | Intel(R) Xeon(R) CPU 3065@2.33GHz |
| Vendor        | Intel Corp. |
| Physical ID   | 4 |
| Bus info      |  cpu@0 |
| Version       | C1 |
| Slot          | CPU 1 |
| Size          | 2012MHz |
| Capacity      | 3300MHz |
| Width         | 64 bits |
| Clock         | 1333MHz |
| Capabilities  | lm fpu fpu_exception wp vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ht tm pbe syscall nx x86-64 constant_tsc arch_perfmon pebs bts rep_good nopl cpuid aperfmperf pni dtes64 monitor ds_cpl smx est tm2 ssse3 cx16 xtpr pdcm lahf_lm pti dtherm cpufreq |
| Configuration | cores=2 enabledcores=2 threads=2 |

Der Server ist insgesamt 6 GB (2 x 2GB, 2 x 1 GB) RAM bestückt. Es handelt sich um SDR2 ECC RAM mit 800 MHz Taktfrequenz. 

Der Server ist mit den folgenden Laufwerken (Festplatten mit Magnetspeicher) ausgestattet:

| # | Description | Product          | Vendor          | Physical ID  | Bus info     | Logical name | Version | Serial          | Size           |
| - | ----------- | ---------------- | --------------- | ------------ | ------------ | -------------| ------- | --------------- | -------------- |
| 0 | ATA Disk    | GB0160CAABV      |                 | 0            | scsi@0:0.0.0 | /dev/sda     | HPG1    | 5RX79N7K        | 149GiB (160GB) |
| 1 | ATA Disk    | WDC WD10EARS-00Y | Western Digital | 1            | scsi@0:0.1.0 | /dev/sdb     | 0A80    | WD-WCAV58006740 | 931GiB (1TB)   |
| 2 | ATA Disk    | GB0160CAABV      |                 | 2            | scsi@1:0.0.0 | /dev/sdc     | HPG1    | 5RX795WB        | 149GiB (160GB) |
| 3 | ATA Disk    | WDC WD10EARS-00Y | Western Digital | 3            | scsi@1:0.1.0 | /dev/sdd     | 0A80    | WD-WCAV58065900 | 931GiB (1TB)   |

## Netzeinbindung

Der Server ist über eine Gigabit-Ethernetschnittstelle mit dem lokalen Netz der Starship Factory verbunden. Der primäre Hostname ist ***cloud.lab.starship-factory.ch***. Es sind die folgenden DNS-Einträge gesetzt:


| Netzwerk | Hostnamen                                                    | IPv4          | Bemerkung                    |
| -------- | ------------------------------------------------------------ | ------------- | ---------------------------- |
| LAN      | cloud.lab.starship-factory.ch<br />ldab.lab.starship-factory.chsind | 100.64.1.200  | Interne Adresses des Servers |
| WAN      | cloud.lab.starship-factory.ch<br />ldap.lap.starship-factory.ch | 5.226.148.123 | Externe Adresse des Routers  |

Auf dem WAN-Router sind für IPv4 die folgenden Port-Weiterleitungen eingerichtet:

| Dienst | Port WAN-Router | Port Cloud-Server |
| ------ | --------------- | ----------------- |
| http   | 80              | 80                |
| https  | 443             | 443               |
| ssh    | 49160           | 22                |

## Grundkonfiguration

Als Betriebssystem kommt *GNU/Linux* zum Einsatz. Als Distribution wird [OpenMediaVault](https://www.openmediavault.org/), welches auf *Debian* basiert, verwendet. 

Soweit nicht anders angegeben, wurden zusätzliche Pakete/Software stets aus dem offiziellen Debian-Repository mittels *apt* installiert. Aktuell sind die folgenden Komponenten zusätzlich installiert:

* System Security Services Daemon
* Uncomplicated Firewall
* Fail2Ban
* Let's encrypt Certbot
* Docker

### Volumen und Partitionierung

Die Laufwerke sind wie folgt partitioniert und in das Dateisystem eingebunden:

| # | Logical name | Partition | Mountpoint                           | Bemerkungen  |
| - | ------------ | --------- | ------------------------------------ | ------------ |
| 0 | sda          | sda1      | /boot                                |              |
|   |              | sda2      |                                      |              |
|   |              |   md0     |                                      | RAID0 device |
|   |              |     md0p1 | [SWAP]                               |              |
|   |              |     md0p2 | /                                    |              |
| 1 | sdb          | md1       | /srv/dev-disk-by-id-md-name-debian-1 | RAID0 device |
| 2 | sdc          | sdc1      | /boot                                | Not used     |
|   |              | sdc2      |                                      |              |
|   |              |   md0     |                                      | RAID0 device |
|   |              |     md0p1 | [SWAP]                               |              |
|   |              |     md0p2 | /                                    |              |
| 3 | sdd          | md1       | /srv/dev-disk-by-id-md-name-debian-1 | RAID0 device |

Die RAID-Speicher sind als Soft-Raids mittels *md* konfiguriert. Der Bootloader *Grub* ist im MBR des Laufwerks *sda* installiert. Er ist so konfiguriert, dass er aus der Partition *sda1* bootet.  

Das Verzeichnis */var/lib/docker/volumes* wurde mittels eines symbolischen Links vom Wurzeldateisystem auf *md0p2* in das Verzeichnis */srv/dev-disk-by-id-md-name-debian-1/docker/volumes* auf der grösseren Datenpartition *md1* verlagert.

### Openmediavault

Die Web-Konfigurationsoberfläche von *OpenMediaVault* ist über die folgenden Adressen zu erreichen:

| Protokoll | URL                   |
| --------- | --------------------- |
| http      | http://<host\>:5000/  |
| https     | https://<host\>:5001/ |

Die Anfrage via *http* wird automatisch auf *https* umgeleitet. Bisher wurde nur ein selbstgezeichnetes Zertifikat hinterlegt, so dass beim ersten Zugriff eine Ausnahmeregel eingerichtet werden muss.

Die Anmeldung erfolgt mittels des Benutzers *admin* oder eines anderen zuvor angelegten Benutzerkontos. Die System-Administratoren wurden der Unix-Gruppe *openmediavault-admin* hinzugefügt, um ihnen administrative Rechte innerhalb der Konfigurationsoberfläche zu gewähren. 

Die Konfiguration von OMV wurde mittels der folgenden Einträge in der Systemkonfigurationsdatei angepasst:

**/etc/default/openmediavault**

    ...
    OMV_NFSD_MOUNTDOPTS="-p 32767"

Der Eintrag für *OMV_NFSD_MOUNTDOPTS* zwingt den *NFS-mountd* auf einen festen Port, so dass eine statische Firewall-Regel angelegt werden kann. Informationen zur erweiterten Konfiguration können dem [OMV-Handbuch](https://openmediavault.readthedocs.io/en/5.x/various/advset.html) entnommen werden.

Die restliche Konfiguration wurde mittels der Konfigurations-Oberfläche vorgenommen und ist im Folgenden nicht weiter dokumentiert.

### Sicherheit

Das Authentifizierungssystem ist um den *System Security Services Demon (sssd)* erweitert, um die Authentifizierung gegen *LDAP* zu ermöglichen. Die LDAP-Benutzer werden lokal zwischengespeichert, so dass die Autentifizierung auch im Fall eines Ausfalls des LDAP-Servers weiterhin möglich ist.

**/etc/sssd/sssd.conf**

    [sssd]
    config_file_version = 2
    services = nss, pam
    domains = starship-factory.ch
    #debug = 7
    
    [nss]
    filter_groups = root
    filter_users = root
    #debug = 7
    
    [pam]
    
    [domain/starship-factory.ch]
    # SSSD can resolve user information from a number of different sources
    # such as LDAP, local files, and Active Directory. This option sets
    # the domain's source of identity information. 
    id_provider = ldap
    
    # As with identity providers, SSSD can authenticate in a variety of ways.
    # By default, SSSD will use the value of id_provider.
    #auth_provider = ldap
    
    # The access provider controls the source for determining who is allowed
    # to access the system. Even if a user successfully authenticates, if they
    # don't meet the criteria provider by the access provider, they will be
    # denied access.
    access_provider = ldap
    
    # The verbosity of this domains log file.
    #debug = 7
    
    # Enumeration is discouraged for performance reasons.
    enumerate = true
    
    # The URI(s) of the directory server(s) used by this domain.
    ldap_uri = ldaps://ldap.lab.starship-factory.ch
    
    # The LDAP search base you want SSSD to use when looking
    # for entries. There are options for search bases for various types
    # of searches, such as users. Read the sssd-ldap man page for details.
    ldap_search_base = dc=starship-factory,dc=ch
    
    # The DN used to search your directory with. It must have read access to
    # everything your system needs.
    ldap_default_bind_dn = cn=omv-ldap-user,ou=system-users,dc=starship-factory,dc=ch
    
    # The password of the bind DN.
    ldap_default_authtok = <Passwort>
    
    # This enables or disables credential caching. I.e. after successfully
    # authenticating a user, the credentials will be stored locally. If the 
    # domain is unavailable, users will still be able to login using the 
    # cached information.
    cache_credentials = true
    
    # By default, the credential cache never expires. If you want sssd to 
    # remove cached credentials, this option will cause them to expire 
    # after the number of days it is set to.
    #account_cache_expiration = 0
    
    # These define the criteria the access provider uses to control who
    # is allowed to login. In this case, any user that matches the 
    # LDAP filter in this example will be allowed access. Any entry
    # that has an objectClass of posixAccount will be allowed access.
    ldap_access_order = filter
    ldap_access_filter = (objectClass=posixAccount)
    
    # The file containing CA certificates you want sssd to trust.
    ldap_tls_cacert = /etc/ssl/certs/ca-certificates.crt
    
    # The TLS ciphers you wish to use. SSSD uses OpenSSL style cipher
    # suites
    #ldap_tls_cipher_suite = HIGH
    
    # This defines how sssd will handle server certificates. Demand means
    # that we are requiring the host portion of the URI to match the
    # certificate's subject or an SAN, the current time is within the valid
    # times on the certificate, and that it's signing chain ends with a CA
    # in the file defined by ldap_tls_cacert.
    ldap_tls_reqcert = demand
    
    # Use this if users are being logged in at /.
    # This example specifies /home/DOMAIN-FQDN/user as $HOME.  Use with pam_mkhomedir.so
    override_homedir = /home/%u
    
    # Always use bash shell. This is required since Synology diskstation 
    # returns "sh" as the default setting and the shell cannot be modified
    # in the web interface. 
    override_shell = /bin/bash

Um die Sicherheit zu erhöhen, ist die *Uncomplicated Firewall (ufw)* installiert und aktiviert. Die *default policy* ist *deny*. Die folgenden Ports bzw. Anwendungen sind für den externen Zugriff freigegeben:

```3
To                         Action      From
--                         ------      ----
Samba                      ALLOW       Anywhere                  
21/tcp                     ALLOW       Anywhere                  
5001                       ALLOW       Anywhere                  
5000                       ALLOW       Anywhere                  
32767                      ALLOW       Anywhere                  
NFS                        ALLOW       Anywhere                  
SSH                        ALLOW       Anywhere                  
WWW                        ALLOW       Anywhere                  
WWW Secure                 ALLOW       Anywhere                  
LDAP                       ALLOW       Anywhere                  
LDAPS                      ALLOW       Anywhere                  
Samba (v6)                 ALLOW       Anywhere (v6)             
21/tcp (v6)                ALLOW       Anywhere (v6)             
5001 (v6)                  ALLOW       Anywhere (v6)             
5000 (v6)                  ALLOW       Anywhere (v6)             
32767 (v6)                 ALLOW       Anywhere (v6)             
NFS (v6)                   ALLOW       Anywhere (v6)             
SSH (v6)                   ALLOW       Anywhere (v6)             
WWW (v6)                   ALLOW       Anywhere (v6)             
WWW Secure (v6)            ALLOW       Anywhere (v6)             
LDAP (v6)                  ALLOW       Anywhere (v6)             
LDAPS (v6)                 ALLOW       Anywhere (v6)
```

Der Port 21 ist für den FTP-Dienst geöffnet, die Ports 5000 und 5001 für die OMV-Konfigurationsoberfläche (*http* und *https*). Der Port 32767 wird für die Verbindung zum NFS-mountd benötigt.

Weiterhin ist das Paket *fail2ban* installiert, um *"Brute force"*-Angriffen vorzubeugen. Die Möglichkeit der Anmeldung von *root* mittels *SSH* wurde deaktiviert.

### Reverse Proxy

Auf dem Cloud-Server ist ein *Nginx*-Web-Server installiert und als inverser Proxy konfiguriert. Über diesen werden externe *http*-Anfragen an die Docker-Container weitergeleitet und gegebenenfalls verschlüsselt (*https*). Konkret ermöglicht der Reverse Proxy den Zugriff auf die *NextCloud*-Instanz sowie die Konfigurationsoberflächen für den *LDAP*-Server.

Die Konfiguration ist in der Datei */etc/nginx/sites-available/nextcloud-reverse-proxy* hinterlegt. Die Konfiguration ist durch Verlinkung in das Verzeichnis */etc/nginx/sites-enabled* aktiviert.

**/etc/nginx/sites-available/nextcloud-reverse-proxy**

    server {
        listen 80;
        server_name cloud.lab.starship-factory.ch ldap.lab.starship-factory.ch;
    
        if ($host = ldap.lab.starship-factory.ch) {
            return 301 https://$host$request_uri;
        } # managed by Certbot
        
        if ($host = cloud.lab.starship-factory.ch) {
            return 301 https://$host$request_uri;
        } # managed by Certbot
    
        return 404; # managed by Certbot
    }
    
    server {
        listen 443 ssl;
        server_name cloud.lab.starship-factory.ch;                                                       
        # Apply letsencrypt nginx ssl configuration
        include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    
        # If you use Lets Encrypt, you should just need to change the domain. 
        # Otherwise, change this to the path to full path to your domains public certificate file.
        ssl_certificate /etc/letsencrypt/live/cloud.lab.starship-factory.ch/fullchain.pem; # managed by Certbot
        ssl_certificate_key /etc/letsencrypt/live/cloud.lab.starship-factory.ch/privkey.pem; # managed by Certbot
        ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
    
        # Log Location. the Nginx User must have R/W permissions. Usually by ownership.   
        access_log /var/log/nginx/access.log; 
    
        # Allow up to 512M upload size
        client_max_body_size 512M;
        
        location / {
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_pass http://cloud.lab.starship-factory.ch:8080;
            proxy_read_timeout 30;
        }
    }
    
    server {
        listen 443 ssl;
        server_name ldap.lab.starship-factory.ch;
    
        # Apply letsencrypt nginx ssl configuration
        include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    
        # If you use Lets Encrypt, you should just need to change the domain. 
        # Otherwise, change this to the path to full path to your domains public certificate file.
        ssl_certificate /etc/letsencrypt/live/cloud.lab.starship-factory.ch/fullchain.pem; # managed by Certbot
        ssl_certificate_key /etc/letsencrypt/live/cloud.lab.starship-factory.ch/privkey.pem; # managed by Certbot
        ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
    
        # Log Location. the Nginx User must have R/W permissions. Usually by ownership.   
        access_log /var/log/nginx/access.log;
    
        # Forward to LDAP account manager
        location / { 
            # Allow access from local network, but deny rest of the world.
            allow 100.64.0.0/16;
            deny all;
    
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_pass http://cloud.lab.starship-factory.ch:8100/;
            proxy_read_timeout 30;
        }
    
        # Forward to phpldapadmin
        location /phpldapadmin/ {
            # Allow access from local network, but deny rest of the world.
            allow 100.64.0.0/16;
            deny all;
    
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_pass http://cloud.lab.starship-factory.ch:8090/;
            proxy_read_timeout 30;
        }
    }

***Hinweis:*** Aus Sicherheitsgründen wurde der Zugriff auf die LAP-Konfigurationsoberflächen auf das lokale Netzwerk begrenzt. 

Die SSL-Zertifikate wurden mittels des Let's Encrypt *certbot* erstellt und werden regelmässig erneuert. Hier zu ist das folgende Skript hinterlegt:

**/etc/cron.monthly/renew-certificates**

    #!/bin/bash
    
    # Renew all let's encrypt certificates
    /usr/bin/certbot renew -n

## Backup

Zur Sicherung aller Daten wurde eine externe Sicherung mittels *BackupPC* eingerichtet. Die Sicherung erfolgt auf dem Backup-Server *rueblitorte.de*, welcher sich physikalisch in D-79576 Weil am Rhein, Deutschland befindet. Der Server wird von Bernd Kalbfuss (aka Langweiler) betrieben.

Für den Zugriff mittels SSH wurde der Benutzer *backuppc* angelegt und der Gruppe *ssh* hinzugefügt. Die Authentifizierung erfolgt mittels eines Schlüsselpaares. Dem Benutzer wurden beschränkte sudo-Rechte eingeräumt:

**/etc/sudoers**

    ...
    # Allow backuppc user to run rsync with root privileges
    backuppc ALL=(root) NOPASSWD: /usr/bin/rsync, /usr/local/bin/backup-mode, /usr/local/bin/production-mode
    ...

Um den Rechner in einen für das Backup sicheren Modus zu bringen und im Anschluss wieder zu reaktivieren, wurden zwei Skripte erstellt. Diese werden von BackupPC vor und nach dem Backup ausgeführt.

**/usr/local/bin/backup-mode**

    #!/bin/bash
    
    echo "Switching host to backup mode."
    
    # Pause critical docker containers
    /usr/bin/docker pause nextcloud
    /usr/bin/docker pause database

**/usr/local/bin/production-mode**

```3
#!/bin/bash

echo "Switching host to production mode."

# Unpause critical docker containers
/usr/bin/docker unpause database
/usr/bin/docker unpause nextcloud
```

Um zu verhindern, dass der Server nach einem fehlgeschlagenen/abgebrochenen Backup im Backup-Modus verbleibt, wurde das *crontab* um den folgenden Eintrag erweitert:

**/etc/crontab**

    ...
    # Unpause docker containers in case of failed backup
    00 5    *  *  * root    /usr/local/bin/production-mode >/dev/null 2>&1
    ...

## LDAP

Zur Benutzerverwaltung und Authentifizierung wurde auf dem Cloud-Server ein *OpenLDAP*-Server sowie die Konfigurationsoberflächen *LDAP Account Manager* und *phpldapadmin* installiert. 

Der LDAP-Server kann via *ldap* über der Port 389 unverschlüsselt sowie via *ldaps* über den Port 636 verschlüsselt angesprochen werden. *STARTTLS* auf dem Port 389 wurde bisher **nicht** konfiguriert.

Die Konfigurationsoberfläche *LDAP Account Manager* ist über den Reverse Proxy unter der Adresse https://ldap.lab.starship-factory.ch/ zu erreichen, die Konfigurationsoberfläche *phpldapadmin* unter der der Adresse https://ldap.lab.starship-factory.ch/phpldapadmin/.

Im Normallfall sollte die Konfigurationsoberfläche *LDAP Account Manager* verwendet werden, da diese einen wesentlich höheren Komfort bietet. Für Spezialfälle (z.B. die Verwaltung der Gruppen für die Administratoren und System-Benutzer) muss phpldapadmin verwendet werden, da der LDAP Account Manager entsprechende Funktionen in der freien Version nicht unterstützt.

### Docker

Der *OpenLDAP*-Server sowie die Administrationsoberflächen *LDAP Account Manager* und *phpldapadmin* wurden mittels *Docker* eingerichtet. Konkret wurden hierfür die folgenden Abbilder von *hub.docker.com* mittels `docker pull` bezogen:

| Repository             | Tag    | Image ID     | Size  |
| ---------------------- | ------ | ------------ | ----- |
| osixia/phpldapadmin    | latest | dbb580facde3 | 309MB |
| osixia/openldap        | latest | 31d1d6e16394 | 257MB |
| ldapaccountmanager/lam | stable | 8b4da396b5eb | 384MB |

Die Container wurden mittels `docker-compose` anhand der folgenden Datei erstellt:

**docker-compose.yml**

    version: '3'
    
    volumes:
      db:
      conf:
      certs:
      admin:
      lam:
    
    services:
      ldap:
        image: osixia/openldap
        container_name: openldap
        restart: always
        ports:
          - "389:389"
          - "636:636"
        volumes:
          - db:/var/lib/ldap
          - conf:/etc/ldap
          - certs:/container/service/slapd/assets/certs
        environment:
          - LDAP_ORGANISATION=starship-factory
          - LDAP_DOMAIN=starship-factory.ch
          - LDAP_ADMIN_PASSWORD=<Passwort>
          - LDAP_TLS_CRT_FILENAME=cert.pem
          - LDAP_TLS_KEY_FILENAME=privkey.pem
          - LDAP_TLS_CA_CRT_FILENAME=chain.pem
          - LDAP_TLS_VERIFY_CLIENT=try
          
    phpldapamin:
        image: osixia/phpldapadmin
        container_name: phpldapadmin
        restart: always
        volumes:
          - adminhinzufügt:/var/www/phpldapadmin
        links: 
          - ldap:ldap-host
        ports:
          - "8090:80"
          - "8091:443"
        environment:
          - PHPLDAPADMIN_LDAP_HOSTS=ldap-host
          - PHPLDAPADMIN_HTTPS=false
          
      lam:
        image: ldapaccountmanager/lam:stable
        container_name: lam
        restart: always
        volumes:
          - lam:/var/lib/ldap-account-manager/config
        ports:
          - "8100:80"
        environment:
          - LAM_SKIP_PRECONFIGURE=false
          - LDAP_DOMAIN=starship-factory.ch
          - LDAP_ORGANISATION="Starship Factory"
          - LDAP_BASE_DN=dc=starship-factory,dc=ch
          - LDAP_USERS_DN=ou=users,dc=starship-factory,dc=ch
          - LDAP_GROUPS_DN=ou=groups,dc=starship-factory,dc=ch
          - LDAP_SERVER=ldaps://ldap.lab.starship-factory.ch:636
          - LAM_DISABLE_TLS_CHECK=false
          - LDAP_USER=cn=admin,dc=starship-factory,dc=ch
          - LAM_PASSWORD=<Passwort>
          - LAM_LANG=de_DE

***Hinweis zu ldap:*** Wird der OpenLDAP-Container mittels `docker-compose down` und im Anschluss `docker-compose up -d` erneut erstellt, so kommt es zu einer Fehlermeldung, da die Datei *ldap.conf* im Volumen *ldap_conf* fehlt. Es besteht lediglich ein symbolischer Link auf eine Datei, welche nicht mehr existiert. Der LDAP-Server startet in diesem Fall nicht, wie mittels `docker logs -f openldap` nachvollzogen werden kann. Um den Fehler zu beheben, muss die Datei aus dem Ordner *ldap_conf.bak* ergänzt werden.

***Hinweis zu lam***: Die Option "LAM_SKIP_PRECONFIGURE=false" sollte lediglich bei der ersten Erstellung des Docker-Containers deaktiviert sein. Danach sollte sie auf "true" gesetzt werden. Ansonsten gehen die in der Web-Oberfläche konfigurierten Einstellungen wieder verloren. 

### Konfiguration

Um die mit dem Let's Encrypt *certbot* erstellten Zertifikate dem LDAP-Server verfügbar zu machen, wurde das Skript `renew-certificates` wie erfolgt erweitert:

**/etc/cron.monthly/renew-certificates**

```33
#!/bin/bash

LDAP_CONTAINER=openldap
SRC_PATH=/etc/letsencrypt/live/cloud.lab.starship-factory.ch
DST_PATH=/container/service/slapd/assets/certs

...

# Copy certificates to openldap docker container
docker cp -L ${SRC_PATH}/cert.pem ${LDAP_CONTAINER}:${DST_PATH}
docker cp -L ${SRC_PATH}/privkey.pem ${LDAP_CONTAINER}:${DST_PATH}
docker cp -L ${SRC_PATH}/chain.pem ${LDAP_CONTAINER}:${DST_PATH}
# Restart openldap docker container
docker restart ${LDAP_CONTAINER}
```

Weiterhin wurden in der Konfiguration des *OpenLDAP*-Servers der Gruppe *cn=ldap-admins,ou=groups,dc=starship-factory,dc=ch* vollständige Schreibrechte eingeräumt sowie der Gruppe *cn=ldap-auth-users,ou=groups,dc=starship-factory,dc=ch* vollständge Leserechte. 

**openldap:/etc/ldap/slapd.d/cn=config/olcDatabase=\{1\}mdb.ldif**

    ...
    olcAccess: {0}to * 
      by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage
      by * break
    olcAccess: {1}to attrs=userPassword,shadowLastChange,mail,labeledURI 
      by self write  
      by dn="cn=admin,dc=example,dc=org" write 
      by group.exact="cn=ldap-admins,ou=groups,dc=starship-factory,dc=ch" write 
      by anonymous auth
      by * none
    olcAccess: {2}to * 
      by dn="cn=admin,dc=example,dc=org" write  
      by group.exact="cn=ldap-admins,ou=groups,dc=starship-factory,dc=ch" write 
      by group.exact="cn=ldap-auth-users,ou=groups,dc=starship-factory,dc=ch" read
      by self read
      by * none
    ...

Die erste Gruppe dient zur Verwaltung der Administratoren, die zweite Gruppe zur Anlage von System-Nutzern, welche zur Authentifizierung gegen den LDAP-Server benötigt werden.

***Hinweis:***  Die Datei *olcDatabase=\{1\}mdb.ldif* befindet sich im Docker-Volumen *ldap_conf*, welches im Verzeichnis */srv/dev-disk-by-id-md-name-debian-1/docker/volumes/ldap_conf/* gespeichert ist. Die Modifikation der *OpenLDAP*-Konfiguration sollte im Normalfall mittels des Befehls `ldapmodify` erfolgen. Da alle Versuche, die Zugriffsrechte mittels `ldapmodify` zu manipulieren scheiterten, wurde letztendlich der Weg der direkten Manipulation der Konfigurationsdatei gewählt.

Die Konfiguration von *phpldapadmin* wurde mit den folgenden Einträgen ergänzt, um sicherzustellen, dass der sichere Hash-Algorithmus *SSHA* verwendet wird und die Nummerierung der Benztzer und Gruppen im Bereich >10000 liegt.

**phpldapadmin:/var/www/phpldapadmin/config/config.php**

    ...
    /* Default password hashing algorithm. One of md5, ssha, sha, md5crpyt, smd5,
       blowfish, crypt or leave blank for now default algorithm. */
    $servers->setValue('appearance','pla_password_hash','ssha');
    
    /* This feature allows phpLDAPadmin to automatically determine the next
       available uidNumber for a new entry. */
    $servers->setValue('auto_number','enable',true);
    
    /* The minimum number to use when searching for the next available number
       (only when 'search' is used for auto_number. */
    $servers->setValue('auto_number','min',array('uidNumber'=>10000,'gidNumber'=>10000));

Die erweiterte Konfiguration des *LDAP Account Manager* wurde mittels der Web-Oberfläche durchgeführt und ist im Folgenden nicht weiter beschrieben.

## NextCloud

Zum Austausch von Dateien und Informationen zwischen den Mitgliedern der Starship Factory wurde auf dem Cloud-Server eine *NextCloud*-Intanz installiert. Die *NextCloud* ist über den Reverse Proxy unter der Adresse https://cloud.lab.starship-factory.ch/ zu erreichen. 

### Docker

Die *NextCloud* wurde mittels *Docker* eingerichtet. Konkret wurden hierfür die folgenden Abbilder von *hub.docker.com* mittels `docker pull` bezogen:

| Repository | Tag    | Image ID     | Size  |
| ---------- | ------ | ------------ | ----- |
| nextcloud  | latest | a7a0780a23a7 | 835MB |
| mariadb    | latest | e27cf5bc24fe | 401MB |

Die Container wurden mittels `docker-compose` anhand der folgenden Datei erstellt:

**docker-compose.yml** 

    version: '3'
    
    networks:
      nextcloud:  
    
    volumes:
      nextcloud:
      db:
    
    services:
      db:
        image: mariadb
        container_name: database
        restart: always
        command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW
        volumes:
          - db:/var/lib/mysql
        networks:
          - nextcloud
        environment:
          - MYSQL_ROOT_PASSWORD=<Passwort>
          - MYSQL_PASSWORD=<Passwort>
          - MYSQL_DATABASE=nextcloud
          - MYSQL_USER=<Passwort>
      app:
        image: nextcloud
        container_name: nextcloud
        restart: always
        ports:
          - 8080:80
        links:
          - db
        volumes:
          - nextcloud:/var/www/html
        networks:
          - nextcloud
        environment:
          - MYSQL_PASSWORD=<Passwort>
          - MYSQL_DATABASE=nextcloud
          - MYSQL_USER=nextcloud
          - MYSQL_HOST=db
          - NEXTCLOUD_TRUSTED_DOMAINS=cloud.lab.starship-factory.ch

### Konfiguration

Damit integrierte Apps, insbesondere *OnlyOffice* in Kombination mit dem inversen Proxy und der Weiterleitung von *http* auf *https* funktionieren, wurde in der Datei *config.php* der Eintrag *overwrite.cli.url* auf '' und die Einstellung *overwriteprotocol* auf 'https' gesetzt. Außerdem wurde der vollständige Name des Hosts unter *trusted_domains* eingetragen.

**nextcloud:/var/www/html/config/config.php**

      ...  
      'trusted_domains' => 
      array (
        0 => 'cloud.lab.starship-factory.ch',
      ),
      'overwrite.cli.url' => '',
      'overwriteprotocol' => 'https',
      ...

***Hinweis:*** Die Datei *config.php* befindet sich im Docker-Volumen *nextcloud_nextcloud*, welches im Verzeichnis */srv/dev-disk-by-id-md-name-debian-1/docker/volumes/nextcloud_nextcloud/* gespeichert ist.

Das *crontab* wurde um den folgenden Eintrag erweitert, damit Hintegrundaufgaben in der *NextCloud* zuverlässig ausgeführt werden:

**/etc/crontab**

    ...
    # Execute NextCloud background jobs in docker container
    */5  *  *  *  * root    /usr/bin/docker exec nextcloud runuser -u www-data -- php -f /var/www/html/cron.php >/dev/null 2>&1
    ...

### Authenitifizierung via LDAP

In den Einstellungen unter "LDAP / AD Integration" wurde die Authentifizierung gegen den lokal installierten *LDAP*-Server aktiviert:

[[!img ldap-config.png align="left" width="800" alt="LDAP configuration screenshot"]]

Der System-Benutzer *nextcloud-ldap-user* wurde zuvor im LDAP-Verzeichnis angelegt und in die Gruppe *ldap-admins* aufgenommen, um ihm Schreibrechte auf das LDAP-Verzeichnis zu gewähren.

***Hinweis***: Auf Grund einer Beschränkung in der LDAP-Implementierung in Nextcloud ist es aktuell notwendig, dass der LDAP-Benutzer Schreibrechte auf das Verzeichnis hat, um Benutzern das Ändern ihrer Passwörter zu ermöglichen. 

***Warnung:*** Eine inkorrekte LDAP-Konfiguration - insbesondere die unsachgemäße Manipulation einer existierenden Konfiguration - kann dazu führen, dass die NextCloud-Instanz nicht mehr startet.


### Apps

Die folgenden Apps wurden in NextCloud deaktiviert, da sie mit der Anwendung OnlyOffice kollidieren:

* Collabora Online - Built-in CODE Server
* Collabora Online

Die folgenden Anwendungen wurden zusätzlich installiert und aktiviert:

* Community Document Server
* ONLYOFFICE
* Group Folders
* Decks
* Tasks
* Circles
* Announcements
* Notes

## Portainer

Um die Verwaltung und Pflege der installierten Docker-Container zu erleichtern, wurde zusätzlich ein Portainer-Server in der Community Edition installiert. Die Portainer-Web-Oberfläche ist unter der Adresse https://portainer.lab.starship-factory.ch/ zu erreichen. Aus Sicherheitsgründen wurde der Zugriff auf das lokale Netzwerk beschränkt.

### Docker

Der Portainer-Server wurde ebenfalls als Docker-Container gemäß der offiziellen Installationsanleitung installiert. Zuerst wurde ein Volumen zur permanenten Datenspeicherung erstellt:

    sudo docker volume create portainer_data

Im Anschluss wurde der Container selbst gestartet:

    sudo docker run -d -p 9000:9000 --name portainer \
        --restart=always \
        -v /var/run/docker.sock:/var/run/docker.sock \
        -v portainer_data:/data \
        portainer/portainer-ce:latest

Abweichend von der offiziellen Installationsanleitung wurde lediglich der unverschlüsselte *http*-Port 9000 weitergeleitet. Der Zugriff via *https* wird duch den Reverse Proxy ermöglicht.

### Reverse Proxy

Der Zugriff auf die Portainer-Web-Oberfläche wird wie bei der NextCloud durch den Nginx-Web-Server vermittelt, der als Reverse Proxy konfiguriert wude. Über diesen werden externe http-Anfragen an die Docker-Container weitergeleitet und gegebenenfalls verschlüsselt (*https*). Es werden die selben SSL-Zertifikate wie für den Cloud-Server verwendet. Aus Sicherheitsgründen wurde der Zugriff auf Portainer auf das lokale Netzwerk begrenzt. Die Konfiguration ist in der Datei */etc/nginx/sites-available/portainer* hinterlegt. Die Konfiguration wurde durch Verlinkung in das Verzeichnis */etc/nginx/sites-enabled* aktiviert.

**/etc/nginx/sites-available/portainer**

    server {
        listen 80;
        server_name portainer.lab.starship-factory.ch;
    
        if ($host = portainer.lab.starship-factory.ch) {
            return 301 https://$host$request_uri;
        } # managed by Certbot
    
        return 404; # managed by Certbot
    }
    
    server {
        listen 443 ssl;
        server_name portainer.lab.starship-factory.ch;                                               
    
        # Apply letsencrypt nginx ssl configuration
        include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    
        # If you use Lets Encrypt, you should just need to change the domain. 
        # Otherwise, change this to the path to full path to your domains public certificate file.
        ssl_certificate /etc/letsencrypt/live/cloud.lab.starship-factory.ch/fullchain.pem; # managed by Certbot
        ssl_certificate_key /etc/letsencrypt/live/cloud.lab.starship-factory.ch/privkey.pem; # managed by Certbot
        ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
    
        # Log Location. the Nginx User must have R/W permissions. Usually by ownership.   
        access_log /var/log/nginx/access.log;                                 
    
        # Forward to NextCloud server
        location / {
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_pass http://cloud.lab.starship-factory.ch:9000/;
            proxy_read_timeout 30;
        }

###  Authenifizierung via LDAP

Um die Authentifizierung mitels LDAP zu ermöglichen, wurde ein dedizierter System-Benutzer *portainer-ldap-user* erstellt. Der System-Benutzer wurde in die Gruppe *ldap-auth-users* aufgenommen, um ihm Suchrechte auf das LDAP-Verzeichnis zu gewähren. Die LDAP-Authentifierzung in Portainer wurde entsprechend dem folgenden Bildschirmfoto in Portainer eingerichtet.

[[!img portainer-ldap-config1.png align="left" alt="Portainer LDAP configuration screenshot 1"]]
[[!img portainer-ldap-config2.png align="left" alt="Portainer LDAP configuration screenshot 2"]]

***Hinweis:*** Neue Benutzer erscheinen erst nach dem ersten erfolgreichen Login in der Portainer-Nutzerverwaltung. Sie haben zu Beginn noch keine Rechte. Diese müssen ihnen im Anschluss explizit durch einen Administrator hinzugefügt werden.