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
|
* Tasks - v3
** DONE Fix Nextcloud 502 error
CLOSED: [2020-08-05 mer. 06:59]
** TODO Add borg backup to crontab
** TODO Add missing =defaul= nginx vhost file
** TODO Clean-up garbage backups from rsync.net
** TODO Harden the server
*** TODO [#C] [[https://www.reddit.com/r/selfhosted/comments/bw8hqq/top_3_measures_to_secure_your_virtual_private/][Top 3 measures to secure your Virtual Private Server? (VPS)]]
*** TODO [#A] [[https://docs.nextcloud.com/server/stable/admin_manual/installation/harden_server.html][Nextcloud: Hardening and security guidance]]
*** TODO [#A] [[https://ownyourbits.com/2017/03/25/nextcloud-a-security-analysis/][NextCloud, a security analysis]]
*** TODO [#B] [[https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/HTTP_Strict_Transport_Security_Cheat_Sheet.md][Check for HSTS header configuration]]
** TODO README with setup instructions
** TODO Fix =file: command not found= in CI
The =file= package is imported in =shell.nix= but =~/.buildenv= is sourced before.
** TODO Use =--pure= for =nix-shell= scripts
** TODO Add volume to fstab
Can I use Terraform form this?
** TODO Use Guix instead of Ansible
Or NixOps if not possible or feasible with Guix.
* Services - v2
** DONE =cloud.$tld=: Nextcloud: storage, calendar, contacts, notes and talk
CLOSED: [2020-08-05 mer. 07:00]
** TODO =chat.$tld=: Matrix Synapse server, or a XMPP server
https://zingmars.info/2019/12/29/Running-a-personal-Matrix-server-using-docker/
https://matrix.org/docs/guides/free-small-matrix-server
https://jonnev.se/matrix-homeserver-with-docker/
** CANCELLED =gpodder.$tld=: gpodder.net sync service
Instead use a desktop application (like gPodder itself) to manage podcasts and export episodes to then phone when needed.
This solution not only doesn't require internet access, but also it removes the mainteinance of additional software on the server.
** TODO =git.$tld=: git-instaweb (or cgit) server with repositories from ~/dev/libre/
** TODO =mail.$tld=: postfix, dovecot, spamassasin, opendkim, etc
No need for roundcube, Nextcloud has a web interface client.
** TODO =$tld=: current Jekyll blog
* Resources
** [[https://github.com/mail-in-a-box/mailinabox][Mail-in-a-Box]]
** [[https://sealedabstract.com/code/nsa-proof-your-e-mail-in-2-hours/][NSA-proof your e-mail in 2 hours]]
** [[https://www.iredmail.org/][iRedMail]]
** [[https://blog.harveydelaney.com/hosting-websites-using-docker-nginx/][Hosting Multiple Websites with SSL using Docker, Nginx and a VPS]]
** [[https://github.com/sovereign/sovereign/][Sovereign]]
** [[https://github.com/nixcloud/nixcloud-webservices][nixcloud-webservices]]
** [[https://github.com/Kickball/awesome-selfhosted#email][Awesome-Selfhosted: Email]]
** [[https://arstechnica.com/information-technology/2014/04/taking-e-mail-back-part-4-the-finale-with-webmail-everything-after/][Taking e-mail back]]
* Decisions
** Use external git repository as an encrypted database
Terraform does have the support for "backends" where it can store =.tfstate= files.
From the list of supported backends, the [[https://www.terraform.io/docs/backends/types/s3.html][S3]] option initially stands out as the simplest to configure. It doesn't however support state locking, only if also configuring DynamoDB.
This extra configuration and complexity isn't attractive, and I can achieve similar outcomes by using the =local= backend and storing it properly. Even better than sending to S3 and setting up the proper revision headers is to just use a separate repository to keep it.
Using the same repository would create an unwanted cyclic process where the repository pipeline commits in itself.
All data stored on git is encrypted with [[https://www.agwa.name/projects/git-crypt/][git-crypt]], which means git isn't being actually used as a source code repository, but as a versioned filesystem database.
By taking advantage of the sourcehut ecosystem, it was easier to setup the access of the pipeline to the ad-hoc Terraform backend.
I created a repository called [[https://git.sr.ht/~euandreh/vps-state/][=vps-state=]] to store the encrypted =.tfstate= and =.tfplan= files. During the CI run, the pipeline creates new a =.tfplan= file and commits it into =vps-state=, and after applying the plan it updates the =.tfstate= file and adds this change to =vps-state=.
** Configuration of =StrictHostKeyChecking=
We have 3 cases where I'm pushing things to the server and I'm dealing with it differently:
*** 1. Pushing updates to the =vps-state= repository
I could whitelist the SSH keys from the =git.sr.ht= servers, but this could break on every key rotation of the server.
In can of the server address being spoofed, the content would be readable by the attacker, since we're doing all the encryption on the client. We would, however, lose a Terraform state file update. As of right now, I'm OK with this trade-off.
*** 2. Running =scp= to the deployed VPS
On this situation I want to be sure I know where I'm pushing to.
In order to avoid adding =StrictHostKeyChecking= when running =ssh= and =scp=, every time the SSH key is rotated I generate a new =./secrets/ssh/known-hosts.txt= file with the proper SSH public key.
This way we can avoid prompting for SSH server fingerprint trust on the CI and avoid adding =StrictHostKeyChecking= on those calls.
*** 3. Backup server
Even though the backup is encrypted before sending the data, I don't want to risk loosing a backup to an spoofed server. I'd rather break the build instead.
** Don't use Ansible as a =local-exec= provisioner from Terraform
Instead, explicitly call =ansible-playbook= after =terraform apply= finished running.
This way we test the DNS A record -> Floating IP -> Droplet IP path. We can't do that inside Terraform declaration because the =local-exec= provisioning command runs before the =digitalocean_floating_ip_assignment= is created, and we can't create a cyclic dependency between the two resources.
We could use the raw Droplet IP instead of the DNS A record, but I prefer calling it later in order to always test the full DNS resolution.
* Scrath
https://federationtester.matrix.org/
EteSync?
|