feat: home-assistant + tewi

This commit is contained in:
Kat Inskip 2022-09-16 23:23:58 -07:00
parent 57e48cd9a8
commit ec7571171b
Signed by: kat
GPG key ID: 465E64DECEA8CF0F
15 changed files with 322 additions and 113 deletions

View file

@ -116,6 +116,7 @@ in
connection = tf.resources."${config.networking.hostName}".connection.set;
};
connection = {
port = lib.head config.services.openssh.ports;
};
};

6
home/gui/nextcloud.nix Normal file
View file

@ -0,0 +1,6 @@
{ config, ... }: {
services = {
nextcloud-client.enable = true;
gnome-keyring.enable = true;
};
}

View file

@ -1,4 +1,45 @@
{ config, pkgs, lib, root, ... }: {
{ config, pkgs, lib, root, ... }: with lib; let
home = config.deploy.targets.home.tf;
in {
options = {
tailnet_uri = mkOption {
type = types.str;
};
tailnet = mkOption {
type = types.attrsOf (types.submodule ({ name, ... }: {
options = {
addresses = {
ipv4 = mkOption {
type = types.str;
};
ipv6 = mkOption {
type = types.str;
};
};
tags = mkOption {
type = types.listOf types.str;
};
};
}));
};
};
config = {
tailnet_uri = "inskip.me";
tailnet = let
raw = home.resources.tailnet_devices.importAttr "devices";
devices = mapListToAttrs (elet: nameValuePair (removeSuffix ".${config.tailnet_uri}" elet.name) {
tags = elet.tags;
addresses = let
addresses = elet.addresses;
ipv4 = head (filter (e: hasInfix "." e) addresses);
ipv6 = head (filter (e: hasInfix ":" e) addresses);
in {
inherit ipv4 ipv6;
};
}) raw;
in devices;
runners = {
lazy = {
file = ./default.nix;
@ -14,4 +55,5 @@
deploy.targets.dummy.enable = false;
_module.args.pkgs = lib.mkDefault pkgs;
};
}

7
nixos/gui/nextcloud.nix Normal file
View file

@ -0,0 +1,7 @@
{ config, ... }: {
services.gnome = {
gnome-keyring.enable = true;
};
security.pam.services.lightdm.enableGnomeKeyring = true;
programs.seahorse.enable = true;
}

View file

@ -1,10 +1,11 @@
{ config, lib, tf, pkgs, meta, ... }: with lib;
{
options.network = with lib; {
routeDefault = mkOption {
default = true;
type = types.bool;
{ config, lib, tf, pkgs, meta, ... }: with lib; let
in {
options = with lib; {
network = {
routeDefault = mkOption {
default = true;
type = types.bool;
};
};
};
@ -31,12 +32,29 @@
};
};
kw.secrets.variables.tailscale-authkey = {
path = "secrets/tailscale";
field = "password";
deploy.tf = {
variables.tailscale-apikey = {
value.shellCommand = "${meta.kw.secrets.command} secrets/tailscale -f api_key";
sensitive = true;
export = true;
};
providers.tailscale = {
inputs = {
api_key = tf.variables.tailscale-apikey.ref;
tailnet = "inskip.me";
};
};
variables.tailscale-authkey.export = true;
resources.tailnet_key = {
provider = "tailscale";
type = "tailnet_key";
inputs = {
reusable = false;
ephemeral = false;
preauthorized = true;
};
};
};
deploy.tf.variables.tailscale-authkey.export = true;
networking.firewall = {
trustedInterfaces = [ "tailscale0" ];
@ -71,7 +89,7 @@
fi
# otherwise authenticate with tailscale
${tailscale}/bin/tailscale up -authkey ${tf.variables.tailscale-authkey.get}
${tailscale}/bin/tailscale up -authkey ${tf.resources.tailnet_key.getAttr "key"}
'';
};
};

View file

@ -1,107 +1,83 @@
{ config, lib, ... }: {
{ config, lib, tf, ... }: {
kw.secrets.variables.ha-integration = {
path = "secrets/home-assistant";
field = "notes";
};
secrets.files.ha-integration = {
text = tf.variables.ha-integration.ref;
owner = "hass";
group = "hass";
};
systemd.services.home-assistant = {
preStart = lib.mkBefore ''
rm ${config.services.home-assistant.configDir}/integration.json
cp --no-preserve=mode ${config.secrets.files.ha-integration.path} ${config.services.home-assistant.configDir}/integration.json
'';
};
services.home-assistant = {
enable = true;
config = {
automation = "automations.yaml";
config = null;
counter = null;
device_tracker = null;
dhcp = null;
energy = null;
frontend = { themes = "themes"; };
google_assistant = null;
group = "groups.yaml";
history = null;
homeassistant = {
external_url = "https://home.gensokyo.zone";
packages = "packages";
default_config = {};
google_assistant = {
project_id = "gensokyo-5cfaf";
service_account = "!include integration.json";
};
http = {
cors_allowed_origins = [
"https://google.com"
"https://www.home-assistant.io"
];
use_x_forwarded_for = "true";
trusted_proxies = [
"127.0.0.0/24"
"200::/7"
"100.64.0.0/10"
"fd7a:115c:a1e0:ab12::/64"
];
use_x_forwarded_for = true;
};
image = null;
input_boolean = null;
input_datetime = null;
input_number = null;
input_select = null;
input_text = null;
logbook = null;
homeassistant = {
name = "Gensokyo";
unit_system = "metric";
external_url = "https://home.gensokyo.zone";
};
logger = {
default = "info";
};
device_tracker = null;
map = null;
media_source = null;
mobile_app = null;
my = null;
person = null;
recorder = {
auto_purge = true;
commit_interval = 1;
exclude = {
domains = [
"automation"
"updater"
];
entities = [
"sun.sun"
"sensor.last_boot"
"sensor.date"
"sensor.time"
];
entity_globs = [
"sensor.weather_*"
"sensor.date_*"
];
event_types = [
"call_service"
];
};
purge_keep_days = 14;
db_url = "postgresql://@/hass";
};
homekit = {
name = "Tewi";
port = 21063;
ip_address = "10.1.1.38";
};
scene = "scenes.yaml";
script = "scripts.yaml";
ssdp = null;
stream = null;
sun = null;
switch = null;
system_health = null;
tag = null;
template = null;
timer = null;
tts = [{
platform = "google_translate";
service_name = "google_say";
}];
wake_on_lan = null;
webhook = null;
zeroconf = null;
zone = null;
};
extraPackages = python3Packages: with python3Packages; [
psycopg2
securetar
];
extraComponents = [
"zha"
"esphome"
"apple_tv"
"spotify"
"default_config"
"cast"
"plex"
"google"
"google_assistant"
"google_cloud"
"google_translate"
"homekit"
"mqtt"
"wake_on_lan"
"zeroconf"
"esphome"
"apple_tv"
"spotify"
"default_config"
"cast"
"plex"
"met"
"google"
"google_assistant"
"google_cloud"
"google_translate"
"homekit"
"mqtt"
"wake_on_lan"
"zeroconf"
];
};
}
}

View file

@ -4,12 +4,23 @@
field = "z2m";
};
kw.secrets.variables.hass-pass = {
path = "secrets/mosquitto";
field = "hass";
};
secrets.files.z2m-pass = {
text = tf.variables.z2m-pass.ref;
owner = "mosquitto";
group = "mosquitto";
};
secrets.files.hass-pass = {
text = tf.variables.hass-pass.ref;
owner = "mosquitto";
group = "mosquitto";
};
services.mosquitto = {
enable = true;
persistence = true;
@ -18,10 +29,16 @@
"pattern readwrite #"
];
users = {
hass = {
passwordFile = config.secrets.files.hass-pass.path;
acl = [
"readwrite #"
];
};
z2m = {
passwordFile = config.secrets.files.z2m-pass.path;
acl = [
"topic readwrite zigbee2mqtt/#"
"readwrite #"
];
};
};

View file

@ -0,0 +1,69 @@
{ config, lib, pkgs, tf, ... }:
with lib;
{
secrets.files.dns_creds = {
text = ''
RFC2136_NAMESERVER='${tf.variables.katdns-address.ref}'
RFC2136_TSIG_ALGORITHM='hmac-sha512.'
RFC2136_TSIG_KEY='${tf.variables.katdns-name.ref}'
RFC2136_TSIG_SECRET='${tf.variables.katdns-key.ref}'
'';
};
network.firewall = {
public.tcp.ports = [ 443 80 ];
private.tcp.ports = [ 443 80 ];
};
services.nginx = {
enable = true;
recommendedGzipSettings = true;
recommendedOptimisation = true;
recommendedProxySettings = true;
recommendedTlsSettings = true;
commonHttpConfig = ''
map $scheme $hsts_header {
https "max-age=31536000; includeSubdomains; preload";
}
add_header Strict-Transport-Security $hsts_header;
#add_header Content-Security-Policy "script-src 'self'; object-src 'none'; base-uri 'none';" always;
add_header 'Referrer-Policy' 'origin-when-cross-origin';
#add_header X-Frame-Options DENY;
#add_header X-Content-Type-Options nosniff;
#add_header X-XSS-Protection "1; mode=block";
#proxy_cookie_path / "/; secure; HttpOnly; SameSite=strict";
'';
clientMaxBodySize = "512m";
virtualHosts = {
"gensokyo.zone" = {
forceSSL = true;
enableACME = true;
locations."/" = {
root = pkgs.gensokyoZone;
};
};
"home.${config.network.dns.domain}" = {
forceSSL = true;
enableACME = true;
locations = {
"/" = {
proxyPass = "http://127.0.0.1:8123";
extraConfig = ''
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_http_version 1.1;
'';
};
};
};
};
};
security.acme = {
defaults.email = config.network.dns.email;
#email = config.network.dns.email;
acceptTerms = true;
};
}

View file

@ -1,11 +1,13 @@
{ meta, config, lib, pkgs, modulesPath, ... }:
{
imports = [
imports = with meta; [
(modulesPath + "/installer/scan/not-detected.nix")
nixos.network
./home-assistant.nix
./zigbee2mqtt.nix
./mosquitto.nix
./postgres.nix
];
deploy.tf = {
@ -29,6 +31,9 @@
};
network = {
firewall = {
public.interfaces = lib.singleton "eno1";
};
addresses = {
private = {
enable = true;

View file

@ -0,0 +1,13 @@
{ config, pkgs, ... }: {
services.postgresql = {
enable = true;
package = pkgs.postgresql_14;
ensureDatabases = [ "hass" ];
ensureUsers = [{
name = "hass";
ensurePermissions = {
"DATABASE hass" = "ALL PRIVILEGES";
};
}];
};
}

View file

@ -6,8 +6,13 @@
log_level = "info";
network_key = "!secret network_key";
};
mqtt = {
server = "mqtt://127.0.0.1:1883";
user = "z2m";
password = tf.variables.z2m-mqtt-password.ref;
};
homeassistant = true;
permit_join = true;
permit_join = false;
frontend = {
port = 8072;
};
@ -18,6 +23,11 @@
};
};
kw.secrets.variables.z2m-mqtt-password = {
path = "secrets/mosquitto";
field = "z2m";
};
kw.secrets.variables.z2m-network-key = {
path = "secrets/zigbee2mqtt";
field = "password";
@ -40,6 +50,6 @@
cp --no-preserve=mode ${config.secrets.files.zigbee2mqtt-secret.path} "${cfg.dataDir}/secret.yaml"
'';
network.firewall.public.tcp.ports = [ 8123 8072 1883 ];
network.firewall.public.tcp.ports = [ 8123 8072 1883 21064 21063 ];
network.firewall.private.tcp.ports = [ 8123 ];
}

View file

@ -14,4 +14,15 @@ final: prev: {
wezterm = final.callPackage ./wezterm {
inherit (final.darwin.apple_sdk.frameworks) Cocoa CoreGraphics Foundation UserNotifications;
};
terraform-providers = prev.terraform-providers // {
tailscale = final.terraform-providers.mkProvider rec {
owner = "tailscale";
provider-source-address = "registry.terraform.io/${owner}/${owner}";
repo = "terraform-provider-tailscale";
rev = "v${version}";
sha256 = "sha256-/qC8TOtoVoBTWeAFpt2TYE8tlYBCCcn/mzVQ/DN51YQ=";
vendorSha256 = "sha256-8EIxqKkVO706oejlvN79K8aEZAF5H2vZRdr5vbQa0l4=";
version = "0.13.5";
};
};
}

View file

@ -5,7 +5,6 @@
cname = { inherit (config.network.addresses.public) target; };
};
deploy.tf.dns.records.services_cloud = {
inherit (config.network.dns) zone;
domain = "cloud";
@ -18,6 +17,12 @@
cname = { inherit (config.network.addresses.public) target; };
};
deploy.tf.dns.records.gensokyo_home = {
zone = "gensokyo.zone.";
domain = "home";
cname = { inherit (config.network.addresses.public) target; };
};
deploy.tf.dns.records.gensokyo_root_v4 = {
zone = "gensokyo.zone.";
a = { inherit (config.network.addresses.public.tf.ipv4) address; };
@ -37,6 +42,20 @@
root = pkgs.gensokyoZone;
};
};
"home.gensokyo.zone" = {
forceSSL = true;
enableACME = true;
locations = {
"/" = {
proxyPass = "http://${meta.tailnet.tewi.addresses.ipv4}:8123";
extraConfig = ''
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_http_version 1.1;
'';
};
};
};
"home.${config.network.dns.domain}" = {
forceSSL = true;
enableACME = true;

View file

@ -1,21 +1,36 @@
{ config, lib, ... }: with lib;
{
deploy.targets.home = {
deploy.targets.home = let meta = config; in {
tf = { config, ... }: {
imports = optional (builtins.pathExists ../services/irlmail.nix) ../services/irlmail.nix;
dns.records.ygg_grimoire = {
zone = "kittywit.ch.";
domain = "grimoire.ygg";
aaaa.address = "200:c87d:7960:916:bf0e:a0e1:3da7:4fc6";
};
variables.tailscale-apikey = {
value.shellCommand = "${meta.kw.secrets.command} secrets/tailscale -f api_key";
sensitive = true;
export = true;
};
dns.records.ygg_boline = {
zone = "kittywit.ch.";
domain = "boline.ygg";
aaaa.address = "200:474d:14f7:1d21:f171:4e85:a3fa:9393";
providers.tailscale = {
inputs = {
api_key = config.variables.tailscale-apikey.ref;
tailnet = "inskip.me";
};
};
resources = {
tailnet_devices = {
type = "devices";
provider = "tailscale";
dataSource = true;
};
tailnet_nr = {
provider = "null";
type = "resource";
inputs.triggers = {
mew = config.resources.tailnet_devices.refAttr "id";
};
};
};
};
};
}

2
tf

@ -1 +1 @@
Subproject commit 856827e23fd7f1ef1d07dea9c5be26c0a0f7dee8
Subproject commit 58d25138fdd294512a311a0fe3c92007f8d55f7a