blob: d24fcf0eb2cf43c8757335704e68a7a440c4281c [file] [log] [blame]
Sergiusz Bazanski73cef112019-04-07 00:06:23 +02001{ config, pkgs, lib, ... }:
2
3with ( import ./toplevel.nix );
4let
5 fqdn = config.networking.hostName + domain;
6 node = (builtins.head (builtins.filter (n: n.fqdn == fqdn) nodes));
7 otherNodes = (builtins.filter (n: n.fqdn != fqdn) nodes);
8
Sergiusz Bazanskib7e4bd42019-05-14 01:44:39 +02009 # Pin for k8s packages. This is so that upagrading the system will not upgrade the k8s control or data planes.
10 k8spkgs = import (fetchGit {
11 name = "nixos-unstable-2019-04-12";
12 url = https://github.com/nixos/nixpkgs/;
13 rev = "1fc591f9a5bd1b016b5d66dfab29560073955a14";
14 }) {};
15
Serge Bazanskid493ab62019-10-31 17:07:19 +010016 infraContainer = pkgs.dockerTools.buildImage {
17 name = "pause";
18 tag = "latest";
19 contents = k8spkgs.kubernetes.pause;
20 config.Cmd = "/bin/pause";
21 };
22
Sergiusz Bazanskib7e4bd42019-05-14 01:44:39 +020023
Sergiusz Bazanski73cef112019-04-07 00:06:23 +020024in rec {
25 imports =
26 [ # Include the results of the hardware scan.
27 ./hardware-configuration.nix
28 ];
29
30 # Use the GRUB 2 boot loader.
31 boot.loader.grub.enable = true;
32 boot.loader.grub.version = 2;
33 boot.loader.grub.device = node.diskBoot;
34
Serge Bazanskid493ab62019-10-31 17:07:19 +010035 boot.kernelPackages = pkgs.linuxPackages_latest;
Sergiusz Bazanski4232c8b2019-04-28 17:12:54 +020036 boot.kernelParams = [ "boot.shell_on_fail" ];
Serge Bazanskid493ab62019-10-31 17:07:19 +010037 boot.kernel.sysctl."net.ipv4.conf.all.rp_filter" = "0";
38 boot.kernel.sysctl."net.ipv4.conf.default.rp_filter" = "0";
Sergiusz Bazanski4232c8b2019-04-28 17:12:54 +020039
Sergiusz Bazanski73cef112019-04-07 00:06:23 +020040 time.timeZone = "Europe/Warsaw";
41
Serge Bazanskid493ab62019-10-31 17:07:19 +010042 networking.useDHCP = false;
43 networking.interfaces."${node.mgmtIf}".useDHCP = true;
44
Sergiusz Bazanski73cef112019-04-07 00:06:23 +020045 # List packages installed in system profile. To search, run:
46 # $ nix search wget
47 environment.systemPackages = with pkgs; [
48 wget vim htop tcpdump
49 rxvt_unicode.terminfo
50 ];
51
52 # Some programs need SUID wrappers, can be configured further or are
53 # started in user sessions.
54 programs.mtr.enable = true;
55
56 # List services that you want to enable:
57 virtualisation.docker.enable = true;
58 virtualisation.docker.extraOptions = "--iptables=false --ip-masq=false --ip-forward=true";
59
60 # Docker 1.13 sets iptables FORWARD to DROP. Unfuck this.
61 systemd.services."docker-iptables-unfuck" = {
62 enable = true;
63 wantedBy = [ "kubernetes.target" ];
64 description = "Docker iptable Unfuck";
65 after = [ "docker.service" ];
66 requires = [ "docker.service" ];
67 path = [ pkgs.iptables ];
68 script = ''
69 iptables -P FORWARD ACCEPT
70 '';
71 serviceConfig.Type = "oneshot";
72 };
Sergiusz Bazanskib7e4bd42019-05-14 01:44:39 +020073 # Otherwise fetchGit nixpkgs pin fails.
74 systemd.services.nixos-upgrade.path = [ pkgs.git ];
Sergiusz Bazanski73cef112019-04-07 00:06:23 +020075
76 # Enable the OpenSSH daemon.
77 services.openssh.enable = true;
78 users.users.root.openssh.authorizedKeys.keys = [
79 "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDD4VJXAXEHEXZk2dxNwehneuJcEGkfXG/U7z4fO79vDVIENdedtXQUyLyhZJc5RTEfHhQj66FwIqzl7mzBHd9x9PuDp6QAYXrkVNMj48s6JXqZqBvF6H/weRqFMf4a2TZv+hG8D0kpvmLheCwWAVRls7Jofnp/My+yDd57GMdsbG/yFEf6WPMiOnA7hxdSJSVihCsCSw2p8PD4GhBe8CVt7xIuinhutjm9zYBjV78NT8acjDUfJh0B1ODTjs7nuW1CC4jybSe2j/OU3Yczj4AxRxBNWuFxUq+jBo9BfpbKLh+Tt7re+zBkaicM77KM/oV6943JJxgHNBBOsv9scZE7 q3k@amnesia"
80 "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDQb3YQoiYFZLKwvHYKbu1bMqzNeDCAszQhAe1+QI5SLDOotclyY/vFmOReZOsmyMFl71G2d7d+FbYNusUnNNjTxRYQ021tVc+RkMdLJaORRURmQfEFEKbai6QSFTwErXzuoIzyEPK0lbsQuGgqT9WaVnRzHJ2Q/4+qQbxAS34PuR5NqEkmn4G6LMo3OyJ5mwPkCj9lsqz4BcxRaMWFO3mNcwGDfSW+sqgc3E8N6LKrTpZq3ke7xacpQmcG5DU9VO+2QVPdltl9jWbs3gXjmF92YRNOuKPVfAOZBBsp8JOznfx8s9wDgs7RwPmDpjIAJEyoABqW5hlXfqRbTnfnMvuR informatic@InformaticPC"
81 "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDGkMgEVwQM8yeuFUYL2TwlJIq9yUNBmHnwce46zeL2PK2CkMz7sxT/om7sp/K5XDiqeD05Nioe+Dr3drP6B8uI33S5NgxPIfaqQsRS+CBEgk6cqFlcdlKETU/DT+/WsdoO173n7mgGeafPInEuQuGDUID0Fl099kIxtqfAhdeZFMM6/szAZEZsElLJ8K6dp1Ni/jmnXCZhjivZH3AZUlnqrmtDG7FY1bgcOfDXAal45LItughGPtrdiigXe9DK2fW3+9DBZZduh5DMJTNlphAZ+nfSrbyHVKUg6WsgMSprur4KdU47q1QwzqqvEj75JcdP1jOWoZi4F6VJDte9Wb9lhD1jGgjxY9O6Gs4CH35bx15W7CN9hgNa0C8NbPJe/fZYIeMZmJ1m7O2xmnYwP8j+t7RNJWu7Pa3Em4mOEXvhBF07Zfq+Ye/4SluoRgADy5eII2x5fFo5EBhInxK0/X8wF6XZvysalVifoCh7T4Edejoi91oAxFgYAxbboXGlod0eEHIi2hla8SM9+IBHOChmgawKBYp2kzAJyAmHNBF+Pah9G4arVCj/axp/SJZDZbJQoI7UT/fJzEtvlb5RWrHXRq+y6IvjpUq4pzpDWW04+9UMqEEXRmhWOakHfEVM9rN8h3aJBflLUBBnh0Z/hVsKNh8bCRHaKtah8TrD9i+wMw== patryk.jakuszew@gmail.com"
82 "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC33naG1ptCvUcRWX9cj9wXM1nW1lyQC4SvMJzWlr9aMD96O8hQ2JMkuIUgUJvorAY02QRplQ2BuoVoVkdkzwjMyi1bL3OdgcKo7Z1yByClGTTocqNJYY0lcUb6EJH8+6e6F9ydrQlSxNzL1uCaA7phZr+yPcmAmWbSfioXn98yXNkE0emHxzJv/nypJY56sDCMC2IXDRd8L2goDtPwgPEW7bWfAQdIFMJ75xOidZOTxJ8eqyXLw/kxY5UlyX66jdoYz1sE5XUHuoQl1AOG9UdlMo0aMhUvP4pX5l7r7EnA9OttKMFB3oWqkVK/R6ynZ52YNOU5BZ9V+Ppaj34W0xNu+p0mbHcCtXYCTrf/OU0hcZDbDaNTjs6Vtcm2wYw9iAKX7Tex+eOMwUwlrlcyPNRV5BTot7lGNYfauHCSIuWJKN4NhCLR/NtVNh4/94eKkPTwJsY6XqDcS7q49wPAs4DAH7BJgsbHPOqygVHrY0YYEfz3Pj0HTxJHQMCP/hQX4fXEGt0BjgoVJbXPAQtPyeg0JuxiUg+b4CgVVfQ6R060MlM1BZzhmh+FY5MJH6nJppS0aHYCvSg8Z68NUlCPKy0jpcyfuAIWQWwSGG1O010WShQG2ELsvNdg5/4HVdCGNl5mmoom6JOd72FOZyQlHDFfeQUQRn9HOeCq/c51rK99SQ== bartek@IHM"
Bartosz Stebelcaa770a2019-05-20 04:26:34 +020083 "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICTR292kx/2CNuWYIsZ6gykQ036aBGrmheIuZa6S1D2x implr@thonk"
Sergiusz Bazanski73cef112019-04-07 00:06:23 +020084 ];
85
86 networking.firewall.enable = false;
87
88 # Point k8s apiserver address at ourselves, as every node runs an apiserver with this cert name.
89 networking.extraHosts = ''
90 127.0.0.1 ${k8sapi}
91 '';
92
93 security.acme.certs = {
94 host = {
95 email = acmeEmail;
96 domain = fqdn;
97 webroot = services.nginx.virtualHosts.host.root;
98 };
99 };
100
101 services.nginx = {
102 enable = true;
103 virtualHosts.host = {
104 serverName = fqdn;
105 root = "/var/www/${fqdn}";
106 };
107 };
108
Serge Bazanskid493ab62019-10-31 17:07:19 +0100109 services.etcd = rec {
Sergiusz Bazanski73cef112019-04-07 00:06:23 +0200110 enable = true;
111 name = fqdn;
112 listenClientUrls = ["https://0.0.0.0:2379"];
113 advertiseClientUrls = ["https://${fqdn}:2379"];
114 listenPeerUrls = ["https://0.0.0.0:2380"];
115 initialAdvertisePeerUrls = ["https://${fqdn}:2380"];
116 initialCluster = (map (n: "${n.fqdn}=https://${n.fqdn}:2380") nodes);
Serge Bazanskid493ab62019-10-31 17:07:19 +0100117 initialClusterState = "existing";
Sergiusz Bazanski73cef112019-04-07 00:06:23 +0200118
119 clientCertAuth = true;
120 trustedCaFile = pki.etcd.server.ca;
121 certFile = pki.etcd.server.cert;
122 keyFile = pki.etcd.server.key;
123
124 peerClientCertAuth = true;
125 peerTrustedCaFile = pki.etcdPeer.ca;
126 peerCertFile = pki.etcdPeer.cert;
127 peerKeyFile = pki.etcdPeer.key;
128
129 extraConf = {
130 PEER_CLIENT_CERT_AUTH = "true";
131 };
132 };
133
134 services.kubernetes = {
Sergiusz Bazanskib7e4bd42019-05-14 01:44:39 +0200135 # Pin to specific k8s package.
136 package = k8spkgs.kubernetes;
Sergiusz Bazanski73cef112019-04-07 00:06:23 +0200137 roles = []; # We do not use any nixpkgs predefined roles for k8s. Instead,
138 # we enable k8s components manually.
139
140 caFile = pki.kube.apiserver.ca;
141 clusterCidr = "10.10.16.0/20";
Sergiusz Bazanski73cef112019-04-07 00:06:23 +0200142
143 path = [ pkgs.e2fsprogs ]; # kubelet wants to mkfs.ext4 when mounting pvcs
144
145 addons.dns.enable = false;
146
Sergiusz Bazanski73cef112019-04-07 00:06:23 +0200147 apiserver = rec {
148 enable = true;
Sergiusz Bazanski4232c8b2019-04-28 17:12:54 +0200149 insecurePort = ports.k8sAPIServerPlain;
Sergiusz Bazanski73cef112019-04-07 00:06:23 +0200150 securePort = ports.k8sAPIServerSecure;
151 advertiseAddress = "${node.ipAddr}";
152
Sergiusz Bazanski4232c8b2019-04-28 17:12:54 +0200153 etcd = {
Sergiusz Bazanskid07861b2019-08-08 17:48:25 +0200154 # https://github.com/kubernetes/kubernetes/issues/72102
155 servers = (map (n: "https://${n.fqdn}:2379") ( [ node ] ));
Sergiusz Bazanski4232c8b2019-04-28 17:12:54 +0200156 caFile = pki.etcd.kube.ca;
157 keyFile = pki.etcd.kube.key;
158 certFile = pki.etcd.kube.cert;
159 };
160
Sergiusz Bazanski73cef112019-04-07 00:06:23 +0200161 tlsCertFile = pki.kube.apiserver.cert;
162 tlsKeyFile = pki.kube.apiserver.key;
163
164 clientCaFile = pki.kube.apiserver.ca;
165
166 kubeletHttps = true;
167 kubeletClientCaFile = pki.kube.apiserver.ca;
168 kubeletClientCertFile = pki.kube.apiserver.cert;
169 kubeletClientKeyFile = pki.kube.apiserver.key;
170
171 serviceAccountKeyFile = pki.kube.serviceaccounts.key;
172
Sergiusz Bazanski4232c8b2019-04-28 17:12:54 +0200173 allowPrivileged = true;
Sergiusz Bazanski73cef112019-04-07 00:06:23 +0200174 serviceClusterIpRange = "10.10.12.0/24";
175 runtimeConfig = "api/all,authentication.k8s.io/v1beta1";
176 authorizationMode = ["Node" "RBAC"];
Sergiusz Bazanskib13b7ff2019-08-29 20:12:24 +0200177 enableAdmissionPlugins = ["Initializers" "NamespaceLifecycle" "NodeRestriction" "LimitRanger" "ServiceAccount" "DefaultStorageClass" "ResourceQuota" "PodSecurityPolicy"];
Sergiusz Bazanski73cef112019-04-07 00:06:23 +0200178 extraOpts = ''
Serge Bazanskid493ab62019-10-31 17:07:19 +0100179 --apiserver-count=5 \
Sergiusz Bazanski73cef112019-04-07 00:06:23 +0200180 --proxy-client-cert-file=${pki.kubeFront.apiserver.cert} \
181 --proxy-client-key-file=${pki.kubeFront.apiserver.key} \
182 --requestheader-allowed-names= \
183 --requestheader-client-ca-file=${pki.kubeFront.apiserver.ca} \
184 --requestheader-extra-headers-prefix=X-Remote-Extra- \
185 --requestheader-group-headers=X-Remote-Group \
186 --requestheader-username-headers=X-Remote-User \
187 -v=5
188 '';
189 };
190
191 controllerManager = {
192 enable = true;
Sergiusz Bazanski4232c8b2019-04-28 17:12:54 +0200193 bindAddress = "0.0.0.0";
194 insecurePort = ports.k8sControllerManagerPlain;
Sergiusz Bazanski73cef112019-04-07 00:06:23 +0200195 leaderElect = true;
196 serviceAccountKeyFile = pki.kube.serviceaccounts.key;
197 rootCaFile = pki.kube.ca;
198 extraOpts = ''
199 --service-cluster-ip-range=10.10.12.0/24 \
200 --use-service-account-credentials=true \
201 --secure-port=${toString ports.k8sControllerManagerSecure}\
202 '';
203 kubeconfig = pki.kube.controllermanager.config;
204 };
205
206 scheduler = {
207 enable = true;
208 address = "0.0.0.0";
209 port = 0;
210 leaderElect = true;
211 kubeconfig = pki.kube.scheduler.config;
212 };
213
214 proxy = {
215 enable = true;
216 kubeconfig = pki.kube.proxy.config;
217 extraOpts = ''
218 --hostname-override=${fqdn}\
219 --proxy-mode=iptables
220 '';
221 };
222
223 kubelet = {
224 enable = true;
225 unschedulable = false;
Sergiusz Bazanski73cef112019-04-07 00:06:23 +0200226 hostname = fqdn;
227 tlsCertFile = pki.kube.kubelet.cert;
228 tlsKeyFile = pki.kube.kubelet.key;
229 clientCaFile = pki.kube.kubelet.ca;
230 nodeIp = node.ipAddr;
231 networkPlugin = "cni";
232 clusterDns = "10.10.12.254";
233 kubeconfig = pki.kube.kubelet.config;
234 extraOpts = ''
235 --cni-conf-dir=/opt/cni/conf \
Sergiusz Bazanski42553cd2019-09-02 16:29:53 +0200236 --cni-bin-dir=/opt/cni/bin \
237 --read-only-port=0
Sergiusz Bazanski73cef112019-04-07 00:06:23 +0200238 '';
239 };
Sergiusz Bazanskib7e4bd42019-05-14 01:44:39 +0200240
241 };
242
243 # https://github.com/NixOS/nixpkgs/issues/60687
244 systemd.services.kube-control-plane-online = {
245 preStart = pkgs.lib.mkForce "";
246 };
247 # this seems to depend on flannel
248 # TODO(q3k): file issue
249 systemd.services.kubelet-online = {
250 script = pkgs.lib.mkForce "sleep 1";
Sergiusz Bazanski73cef112019-04-07 00:06:23 +0200251 };
Sergiusz Bazanskif970a7e2019-06-20 12:51:39 +0200252 # This by default removes all CNI plugins and replaces them with nix-defines ones
253 # Since we bring our own CNI plugins via containers with host mounts, this causes
254 # them to be removed on kubelet restart.
Sergiusz Bazanski0de43682019-06-20 12:55:02 +0200255 # TODO(https://github.com/NixOS/nixpkgs/issues/53601): fix when resolved
Sergiusz Bazanskif970a7e2019-06-20 12:51:39 +0200256 systemd.services.kubelet = {
Serge Bazanskid493ab62019-10-31 17:07:19 +0100257 preStart = pkgs.lib.mkForce ''
258 ${lib.concatMapStrings (img: ''
259 echo "Seeding docker image: ${img}"
260 docker load <${img}
261 '') [infraContainer]}
262 '';
Sergiusz Bazanskif970a7e2019-06-20 12:51:39 +0200263 };
Sergiusz Bazanski73cef112019-04-07 00:06:23 +0200264}