cluster/kube: deploy identd

Change-Id: I9a00487fc4a972ecb0904055dbaaab08221062c1
diff --git a/cluster/kube/lib/identd.libsonnet b/cluster/kube/lib/identd.libsonnet
new file mode 100644
index 0000000..dcc181b
--- /dev/null
+++ b/cluster/kube/lib/identd.libsonnet
@@ -0,0 +1,112 @@
+// Deploys identd, an ident protocol (RFC1413) service on all cluster nodes.
+//
+// See //cluster/identd for more information about the service and how it
+// works.
+//
+// Deployment notes:
+//  - We run the service within the host network namespace, as that's the only
+//    way to reliably route traffic destined for a given node into a service
+//    running on that node. We could use NodePort services, but low-numbered
+//    ports are denied by kubelet with out current configuration.
+//  - We pass the host containerd socket to the service, and the service runs
+//    as root. This means that the service basically has root on the machine.
+//    The fact that it's directly exposed to the Internet isn't great, but the
+//    only alternative seems to to split this up into two services - one
+//    responsible for maintaining the state of translations/pods (running as
+//    root), another responding to the actual queries. Considering this is Go
+//    and we run a bare minimum of code (no mirko default service), this is
+//    probably good enough and not worth the extra complexity.
+//  - The service has to be able to resolve the node IP on which it's running,
+//    to know what address to look up in the conntrack table. Currently it does
+//    so by connection to the k8s API and getting information about its own pod
+//    and then getting the node's IP address from there.
+//    This might be overly complicated, as perhaps we can
+//      1. figure out the server IP from the incoming ident connections, or
+//      2. find a better way to retrieve the nodeIP via the 'downstream API'
+//    TODO(q3k): figure this out.
+
+local kube = import "../../../kube/kube.libsonnet";
+local policies = import "../../../kube/policies.libsonnet";
+
+{
+    Environment: {
+        local env = self,
+        local cfg = env.cfg,
+        cfg:: {
+            namespace: "identd",
+            image: "registry.k0.hswaw.net/q3k/identd:315532800-9f29c14dad77036d0820948139b5aee3fac25d59",
+        },
+
+        namespace: kube.Namespace(cfg.namespace),
+        local ns = self.namespace,
+
+        allowInsecure: policies.AllowNamespaceInsecure(cfg.namespace),
+
+        sa: ns.Contain(kube.ServiceAccount("identd")),
+        role: ns.Contain(kube.Role("access-pod-info")) {
+            rules: [
+                {
+                    apiGroups: [""],
+                    resources: ["pods"],
+                    verbs: ["get"],
+                },
+            ],
+        },
+        rb: ns.Contain(kube.RoleBinding("identd")) {
+            roleRef_: env.role,
+            subjects_: [env.sa],
+        },
+
+        daemonset: ns.Contain(kube.DaemonSet("identd")) {
+            spec+: {
+                template+: {
+                    spec+: {
+                        serviceAccountName: env.sa.metadata.name,
+                        hostNetwork: true,
+                        containers_: {
+                            default: kube.Container("default") {
+                                image: cfg.image,
+                                env_: {
+                                    POD_NAME: kube.FieldRef("metadata.name"),
+                                    POD_NAMESPACE: kube.FieldRef("metadata.namespace"),
+                                },
+                                command: [
+                                    "/cluster/identd/identd",
+                                    "-identd_listen", "0.0.0.0:113",
+                                    "-identd_conntrack_proc", "/host/conntrack",
+                                    "-identd_containerd_socket", "/host/containerd.sock",
+                                    // Used by the service to figure out which
+                                    // node it's running on.
+                                    "-identd_pod_name", "$(POD_NAME)",
+                                    "-identd_pod_namespace", "$(POD_NAMESPACE)",
+                                    "-logtostderr",
+                                ],
+                                volumeMounts_: {
+                                    conntrack: { mountPath: "/host/conntrack", },
+                                    containerd: { mountPath: "/host/containerd.sock", },
+                                },
+                                resources: {
+                                    requests: {
+                                        cpu: "0.1",
+                                        memory: "64M",
+                                    },
+                                    // Allow identd to spike to 1 CPU. This
+                                    // makes it faster when fetching
+                                    // information from containerd.
+                                    limits: {
+                                        cpu: "1",
+                                        memory: "256M",
+                                    },
+                                },
+                            },
+                        },
+                        volumes_: {
+                            conntrack: kube.HostPathVolume("/proc/net/nf_conntrack", "File"),
+                            containerd: kube.HostPathVolume("/var/run/containerd/containerd.sock", "Socket"),
+                        },
+                    },
+                },
+            },
+        },
+    }
+}