From 5f4019a34c682aff306746546d9dcb8205ba9354 Mon Sep 17 00:00:00 2001 From: Pierre Penninckx Date: Sun, 19 Nov 2023 23:11:03 -0800 Subject: [PATCH] reorganize home assistant demo --- .github/workflows/demo.yml | 16 ++ README.md | 8 +- demo/homeassistant/README.md | 195 ++++++++++++++++++ .../homeassistant/configuration.nix | 28 ++- {examples => demo}/homeassistant/flake.lock | 0 {examples => demo}/homeassistant/flake.nix | 17 +- .../homeassistant/hardware-configuration.nix | 0 {examples => demo}/homeassistant/keys.txt | 0 {examples => demo}/homeassistant/secrets.yaml | 0 {examples => demo}/homeassistant/sops.yaml | 2 - {examples => demo}/homeassistant/ssh_config | 0 {examples => demo}/homeassistant/sshkey | 0 {examples => demo}/homeassistant/sshkey.pub | 0 examples/homeassistant/README.md | 164 --------------- 14 files changed, 240 insertions(+), 190 deletions(-) create mode 100644 .github/workflows/demo.yml create mode 100644 demo/homeassistant/README.md rename {examples => demo}/homeassistant/configuration.nix (62%) rename {examples => demo}/homeassistant/flake.lock (100%) rename {examples => demo}/homeassistant/flake.nix (80%) rename {examples => demo}/homeassistant/hardware-configuration.nix (100%) rename {examples => demo}/homeassistant/keys.txt (100%) rename {examples => demo}/homeassistant/secrets.yaml (100%) rename {examples => demo}/homeassistant/sops.yaml (66%) rename {examples => demo}/homeassistant/ssh_config (100%) rename {examples => demo}/homeassistant/sshkey (100%) rename {examples => demo}/homeassistant/sshkey.pub (100%) delete mode 100644 examples/homeassistant/README.md diff --git a/.github/workflows/demo.yml b/.github/workflows/demo.yml new file mode 100644 index 0000000..75fb27d --- /dev/null +++ b/.github/workflows/demo.yml @@ -0,0 +1,16 @@ +name: "Demo" +on: + pull_request: + push: +jobs: + tests: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: cachix/install-nix-action@v22 + with: + github_access_token: ${{ secrets.GITHUB_TOKEN }} + - run: | + for d in ./demo; + do (cd "$d"; nix flake check) + done diff --git a/README.md b/README.md index 3d9a7f3..bac89b1 100644 --- a/README.md +++ b/README.md @@ -166,7 +166,13 @@ imports = [ ] ``` -For how to deploy services, check the examples below. +For how to configure the services, check the sections below. + +## Demos + +Demos that start and deploy on a Virtual Machine on your computer are located under the +[demo](./demo/) folder. These show the onboarding experience you would get if you deployed +selfhostblocks on your own server. ## Examples diff --git a/demo/homeassistant/README.md b/demo/homeassistant/README.md new file mode 100644 index 0000000..1af42fc --- /dev/null +++ b/demo/homeassistant/README.md @@ -0,0 +1,195 @@ +# Home Assistant Demo + +The [`flake.nix`](./flake.nix) file sets up Home Assistant server that uses a LDAP server to +setup users in only about [15 lines](./flake.nix#L29-L45) of related code. + +This guide will show how to deploy this setup to a Virtual Machine, like showed +[here](https://nixos.wiki/wiki/NixOS_modules#Developing_modules), in 5 commands. + +## Deploy to the VM + +Build VM with: + +```bash +nixos-rebuild build-vm-with-bootloader --fast -I nixos-config=./configuration.nix -I nixpkgs=. +``` + +Start VM with (this call is blocking): + +```bash +QEMU_NET_OPTS="hostfwd=tcp::2222-:2222,hostfwd=tcp::8080-:80" ./result/bin/run-nixos-vm +``` + +With the VM started, print the VM's public age key with the following command. The value you need is +the one staring with `age`. + +```bash +$ nix shell nixpkgs#ssh-to-age --command sh -c 'ssh-keyscan -p 2222 -4 localhost | ssh-to-age' +# localshost:2222 SSH-2.0-OpenSSH_9.1 +# localhost:2222 SSH-2.0-OpenSSH_9.1 +# localhost:2222 SSH-2.0-OpenSSH_9.1 +# localhost:2222 SSH-2.0-OpenSSH_9.1 +# localhost:2222 SSH-2.0-OpenSSH_9.1 +skipped key: got ssh-rsa key type, but only ed25519 keys are supported +age1l9dyy02qhlfcn5u9s4y2vhsvjtxj2c9avrpat6nvjd6rjar3tflq66jtz0 +``` + +Now, make the `secrets.yaml` file decryptable in the VM. + +```bash +SOPS_AGE_KEY_FILE=keys.txt nix run --impure nixpkgs#sops -- \ + --config sops.yaml -r -i \ + --add-age age1l9dyy02qhlfcn5u9s4y2vhsvjtxj2c9avrpat6nvjd6rjar3tflq66jtz0 \ + secrets.yaml +``` + +Finally, deploy with: + +```bash +SSH_CONFIG_FILE=ssh_config nix run nixpkgs#colmena --impure -- apply +``` + +This step will require you to accept the host's fingerprint. The deploy will take a few minutes the first time and subsequent deploys will take around 15 seconds. + +## Access Home Assistant Through Your Browser + +Add the following entry to your `/etc/hosts` file: + +```nix +networking.hosts = { + "127.0.0.1" = [ "ha.example.com" "ldap.example.com" ]; +}; +``` + +Which produces: + +```bash +$ cat /etc/hosts +127.0.0.1 ha.example.com ldap.example.com +``` + +Go to [http://ldap.example.com:8080](http://ldap.example.com:8080) and login with: +- username: `admin` +- password: the value of the field `lldap.user_password` in the `secrets.yaml` file which is. + +Create the group `homeassistant_user` and a user assigned to that group. + +Go to [http://ha.example.com:8080](http://ha.example.com:8080) and login with the +user and password you just created above. + +## In More Details + +### Files + +- [`flake.nix`](./flake.nix): nix entry point, defines one target host for + [colmena](https://colmena.cli.rs) to deploy to as well as the selfhostblock's config for + setting up the home assistant server paired with the LDAP server. +- [`configuration.nix`](./configuration.nix): defines all configuration required for colmena + to deploy to the VM. The file has comments if you're interested. +- [`hardware-configuration.nix`](./hardware-configuration.nix): defines VM specific layout. + This was generated with nixos-generate-config on the VM. +- Secrets related files: + - [`keys.txt`](./keys.txt): your private key for sops-nix, allows you to edit the `secrets.yaml` + file. This file should never be published but here I did it for convenience, to be able to + deploy to the VM in less steps. + - [`secrets.yaml`](./secrets.yaml): encrypted file containing required secrets for Home Assistant + and the LDAP server. This file can be publicly accessible. + - [`sops.yaml`](./sops.yaml): describes how to create the `secrets.yaml` file. Can be publicly + accessible. +- SSH related files: + - [`sshkey(.pub)`](./sshkey): your private and public ssh keys. Again, the private key should usually not + be published as it is here but this makes it possible to deploy to the VM in less steps. + - [`ssh_config`](./ssh_config): the ssh config allowing you to ssh into the VM by just using the + hostname `example`. Usually you would store this info in your `~/.ssh/config` file but it's + provided here to avoid making you do that. + +### Virtual Machine + +_More info about the VM._ + +We use `build-vm-with-bootloader` instead of just `build-vm` as that's the only way to deploy to the VM. + +The VM's User and password are both `nixos`, as setup in the [`configuration.nix`](./configuration.nix) file under +`user.users.nixos.initialPassword`. + +You can login with `ssh -F ssh_config example`. You just need to accept the fingerprint. + +### Secrets + +_More info about the secrets._ + +The private key in the `keys.txt` file is created with: + +```bash +$ nix shell nixpkgs#age --command age-keygen -o keys.txt +Public key: age1algdv9xwjre3tm7969eyremfw2ftx4h8qehmmjzksrv7f2qve9dqg8pug7 +``` + +We use the printed public key in the `admin` field in `sops.yaml` file. + +The `secrets.yaml` file must follow the format: + +```yaml +home-assistant: | + name: "My Instance" + country: "US" + latitude_home: "0.100" + longitude_home: "-0.100" + time_zone: "America/Los_Angeles" + unit_system: "metric" +lldap: + user_password: XXX... + jwt_secret: YYY... +``` + +You can generate random secrets with: + +```bash +$ nix run nixpkgs#openssl -- rand -hex 64 +``` + +#### Why do we need the VM's public key + +The [`sops.yaml`](./sops.yaml) file describes what private keys can decrypt and encrypt the +[`secrets.yaml`](./secrets.yaml) file containing the application secrets. Usually, you will create and add +secrets to that file and when deploying, it will be decrypted and the secrets will be copied +in the `/run/secrets` folder on the VM. We thus need one private key for you to edit the +[`secrets.yaml`](./secrets.yaml) file and one in the VM for it to decrypt the secrets. + +Your private key is already pre-generated in this repo, it's the [`sshkey`](./sshkey) file. But when +creating the VM in the step above, a new private key and its accompanying public key were +automatically generated under `/etc/ssh/ssh_host_ed25519_key` in the VM. We just need to get the +public key and add it to the `secrets.yaml` which we did in the Deploy section. + +To open the `secrets.yaml` file and optionnally edit it, run: + +```bash +SOPS_AGE_KEY_FILE=keys.txt nix run --impure nixpkgs#sops -- \ + --config sops.yaml \ + secrets.yaml +``` + +### SSH + +The private and public ssh keys were created with: + +```bash +ssh-keygen -t ed25519 -f sshkey +``` + +You don't need to copy over the ssh public key over to the VM as we set the `keyFiles` option which copies the public key when the VM gets created. +This allows us also to disable ssh password authentication. + +For reference, here is what you would need to do if you didn't use the option: + +```bash +$ nix shell nixpkgs#openssh --command ssh-copy-id -i sshkey -F ssh_config example +``` + +### Deploy + +If you get a NAR hash mismatch error like herunder, you need to run `nix flake lock --update-input selfhostblocks`. + +``` +error: NAR hash mismatch in input ... +``` diff --git a/examples/homeassistant/configuration.nix b/demo/homeassistant/configuration.nix similarity index 62% rename from examples/homeassistant/configuration.nix rename to demo/homeassistant/configuration.nix index 99acf5a..25af783 100644 --- a/examples/homeassistant/configuration.nix +++ b/demo/homeassistant/configuration.nix @@ -20,20 +20,29 @@ # Options above are needed to deploy in a VM. - # As we intend to run this example using `nixos-rebuild build-vm`, we need to setup the user - # ourselves, see https://nixos.wiki/wiki/NixOS:nixos-rebuild_build-vm - users.users.nixos = { + nix.settings.experimental-features = [ "nix-command" "flakes" ]; + + # Used by colmena to know which target host to deploy to. + deployment = { + targetHost = "example"; + targetPort = 2222; + targetUser = "nixos"; + }; + + # We need to create the user we will deploy with. + users.users.${config.deployment.targetUser} = { isNormalUser = true; extraGroups = [ "wheel" ]; # Enable ‘sudo’ for the user. initialPassword = "nixos"; - # With this option, you don't need to use ssh-copy-id. + # With this option, you don't need to use ssh-copy-id to copy the public ssh key to the VM. openssh.authorizedKeys.keyFiles = [ ./sshkey.pub ]; }; + # The user we're deploying with must be able to run sudo without password. security.sudo.extraRules = [ - { users = [ "nixos" ]; + { users = [ config.deployment.targetUser ]; commands = [ { command = "ALL"; options = [ "NOPASSWD" ]; @@ -42,15 +51,16 @@ } ]; - nix.settings.experimental-features = [ "nix-command" "flakes" ]; + # Needed to allow the user we're deploying with to write to the nix store. nix.settings.trusted-users = [ - "nixos" + config.deployment.targetUser ]; + # We need to enable the ssh daemon to be able to deploy. services.openssh = { enable = true; - ports = [ 2222 ]; + ports = [ config.deployment.targetPort ]; permitRootLogin = "no"; - passwordAuthentication = true; + passwordAuthentication = false; }; } diff --git a/examples/homeassistant/flake.lock b/demo/homeassistant/flake.lock similarity index 100% rename from examples/homeassistant/flake.lock rename to demo/homeassistant/flake.lock diff --git a/examples/homeassistant/flake.nix b/demo/homeassistant/flake.nix similarity index 80% rename from examples/homeassistant/flake.nix rename to demo/homeassistant/flake.nix index d48501e..843c08a 100644 --- a/examples/homeassistant/flake.nix +++ b/demo/homeassistant/flake.nix @@ -20,22 +20,12 @@ }; myserver = { config, ... }: { - deployment = { - targetHost = "example"; - targetPort = 2222; - targetUser = "nixos"; - }; - imports = [ ./configuration.nix sops-nix.nixosModules.default selfhostblocks.nixosModules.x86_64-linux.default ]; - # Set to true for more debug info with `journalctl -f -u nginx`. - shb.nginx.accessLog = true; - shb.nginx.debugLog = true; - shb.ldap = { enable = true; domain = "example.com"; @@ -54,10 +44,9 @@ sopsFile = ./secrets.yaml; }; - nix.settings.experimental-features = [ "nix-command" "flakes" ]; - nix.settings.trusted-users = [ - "nixos" - ]; + # Set to true for more debug info with `journalctl -f -u nginx`. + shb.nginx.accessLog = false; + shb.nginx.debugLog = false; }; }; }; diff --git a/examples/homeassistant/hardware-configuration.nix b/demo/homeassistant/hardware-configuration.nix similarity index 100% rename from examples/homeassistant/hardware-configuration.nix rename to demo/homeassistant/hardware-configuration.nix diff --git a/examples/homeassistant/keys.txt b/demo/homeassistant/keys.txt similarity index 100% rename from examples/homeassistant/keys.txt rename to demo/homeassistant/keys.txt diff --git a/examples/homeassistant/secrets.yaml b/demo/homeassistant/secrets.yaml similarity index 100% rename from examples/homeassistant/secrets.yaml rename to demo/homeassistant/secrets.yaml diff --git a/examples/homeassistant/sops.yaml b/demo/homeassistant/sops.yaml similarity index 66% rename from examples/homeassistant/sops.yaml rename to demo/homeassistant/sops.yaml index d2d10b2..b9f8700 100644 --- a/examples/homeassistant/sops.yaml +++ b/demo/homeassistant/sops.yaml @@ -1,9 +1,7 @@ keys: - &admin age1algdv9xwjre3tm7969eyremfw2ftx4h8qehmmjzksrv7f2qve9dqg8pug7 - - &vm age18jrfv0ndtrad7ee4dzdfhhuca4wuce059txltdaxuxcnjkc37s5qj9mapm creation_rules: - path_regex: secrets.yaml$ key_groups: - age: - *admin - - *vm diff --git a/examples/homeassistant/ssh_config b/demo/homeassistant/ssh_config similarity index 100% rename from examples/homeassistant/ssh_config rename to demo/homeassistant/ssh_config diff --git a/examples/homeassistant/sshkey b/demo/homeassistant/sshkey similarity index 100% rename from examples/homeassistant/sshkey rename to demo/homeassistant/sshkey diff --git a/examples/homeassistant/sshkey.pub b/demo/homeassistant/sshkey.pub similarity index 100% rename from examples/homeassistant/sshkey.pub rename to demo/homeassistant/sshkey.pub diff --git a/examples/homeassistant/README.md b/examples/homeassistant/README.md deleted file mode 100644 index 719e82d..0000000 --- a/examples/homeassistant/README.md +++ /dev/null @@ -1,164 +0,0 @@ -# Home Assistant Example - -This `flake.nix` file sets up Home Assistant server that uses a LDAP server to -setup users with only about [15 lines](./flake.nix#L39-L55) of related code. - -This guide will show how to deploy this setup to a Virtual Machine, like showed -[here](https://nixos.wiki/wiki/NixOS_modules#Developing_modules), in 5 commands. - -## Launch VM - -Build VM with: - -```bash -nixos-rebuild build-vm-with-bootloader --fast -I nixos-config=./configuration.nix -I nixpkgs=. -``` - -Start VM with (this call is blocking): - -```bash -QEMU_NET_OPTS="hostfwd=tcp::2222-:2222,hostfwd=tcp::8080-:80" ./result/bin/run-nixos-vm -``` - -User and password are both `nixos`, as setup in the [`configuration.nix`](./configuration.nix) file under -`user.users.nixos.initialPassword`. - -You can login with `ssh -F ssh_config example`. You just need to accept the fingerprint. - -## Make VM able to decrypt the secrets.yaml file - -The [`sops.yaml`](./sops.yaml) file describes what private keys can decrypt and encrypt the -[`secrets.yaml`](./secrets.yaml) file containing the application secrets. Usually, you will add -secrets to that secrets file and when deploying, it will be decrypted and the secrets will be copied -in the `/run/secrets` folder on the VM. We thus need one private key for you to edit the -[`secrets.yaml`](./secrets.yaml) file and one in the VM for it to decrypt the secrets. - -Your private key is already pre-generated in this repo, it's the [`sshkey`](./sshkey) file. But when -creating the VM in the step above, a new private key and its accompanying public key were -automatically generated under `/etc/ssh/ssh_host_ed25519_key` in the VM. We just need to get the -public key. - -With the VM started, print the VM's public age key with the following command. The value you need is -the one staring with `age`. - -```bash -$ nix shell nixpkgs#ssh-to-age --command sh -c 'ssh-keyscan -p 2222 -4 localhost | ssh-to-age' -# localshost:2222 SSH-2.0-OpenSSH_9.1 -# localhost:2222 SSH-2.0-OpenSSH_9.1 -# localhost:2222 SSH-2.0-OpenSSH_9.1 -# localhost:2222 SSH-2.0-OpenSSH_9.1 -# localhost:2222 SSH-2.0-OpenSSH_9.1 -skipped key: got ssh-rsa key type, but only ed25519 keys are supported -age1l9dyy02qhlfcn5u9s4y2vhsvjtxj2c9avrpat6nvjd6rjar3tflq66jtz0 -``` - -Now, make the `secrets.yaml` file decryptable in the VM. - -```bash -SOPS_AGE_KEY_FILE=keys.txt nix run --impure nixpkgs#sops -- \ - --config sops.yaml -r -i \ - --add-age age1l9dyy02qhlfcn5u9s4y2vhsvjtxj2c9avrpat6nvjd6rjar3tflq66jtz0 \ - secrets.yaml -``` - -Later on, when the server is deployed, you will need to login to the LDAP server with the admin account. -You can find the secret `lldap.user_password` field in the [`secrets.yaml`](./secrets.yaml) file. To open it, run: - -```bash -SOPS_AGE_KEY_FILE=keys.txt nix run --impure nixpkgs#sops -- \ - --config sops.yaml \ - secrets.yaml -``` - -## Deploy - -Now, deploy with: - -```bash -SSH_CONFIG_FILE=ssh_config nix run nixpkgs#colmena --impure -- apply -``` - -Took a few minutes for first deploy on my machine. Next deploys take about 12 seconds. - -## Access apps through your browser - -Add the following entry to your `/etc/hosts` file: - -```nix -networking.hosts = { - "127.0.0.1" = [ "ha.example.com" "ldap.example.com" ]; -}; -``` - -Which produces: - -```bash -$ cat /etc/hosts -127.0.0.1 ha.example.com ldap.example.com -``` - -Go to [http://ldap.example.com:8080](http://ldap.example.com:8080) and login with: -- username: `admin` -- password: the value of the field `lldap.user_password` in the `secrets.yaml` file. - -Create the group `homeassistant_user` and a user assigned to that group. - -Go to [http://ha.example.com:8080](http://ha.example.com:8080) and login with the user and password you just created above. - -## Prepare the VM - -This section documents how the various files were created to provide the nearly out of the box -experience described in the previous section. I need to clean this up a bit. - -### Private and Public Key - -Create the private key in the `keys.txt` file and print the public key used for `admin`: - -```bash -$ nix shell nixpkgs#age --command age-keygen -o keys.txt -Public key: age1algdv9xwjre3tm7969eyremfw2ftx4h8qehmmjzksrv7f2qve9dqg8pug7 -``` - -Update `admin` and `vm` keys in `sops.yaml`. - -Then, you can create the secrets.yaml with: - -That file must follow the format: - -```yaml -home-assistant: | - name: "My Instance" - country: "US" - latitude_home: "0.100" - longitude_home: "-0.100" - time_zone: "America/Los_Angeles" - unit_system: "metric" -lldap: - user_password: XXX... - jwt_secret: YYY... -``` - -You can generate secrets with: - -```bash -$ nix run nixpkgs#openssl -- rand -hex 64 -``` - -TODO: add instructions to create ssh private and public key: - -```bash -``` - -You don't need to copy over the ssh public key with the following command as we set the `keyFiles` option. I still leave it here for reference. - -```bash -$ nix shell nixpkgs#openssh --command ssh-copy-id -i sshkey -F ssh_config example -``` - -### Deploy - -If you get a NAR hash mismatch error like so, you need to run `nix flake lock --update-input selfhostblocks`: - -``` -error: NAR hash mismatch in input ... -```