cluster/kube: deploy admitomatic
This doesn't yet enable a webhook, but deploys admitomatic itself.
Change-Id: Id177bc8841c873031f9c196b8ff3c12dd846ba8e
diff --git a/cluster/kube/k0.libsonnet b/cluster/kube/k0.libsonnet
index f393dbe..b5feb05 100644
--- a/cluster/kube/k0.libsonnet
+++ b/cluster/kube/k0.libsonnet
@@ -7,6 +7,7 @@
local cluster = import "cluster.libsonnet";
+local admitomatic = import "lib/admitomatic.libsonnet";
local cockroachdb = import "lib/cockroachdb.libsonnet";
local registry = import "lib/registry.libsonnet";
local rook = import "lib/rook.libsonnet";
@@ -308,5 +309,57 @@
# TODO(implr): restricted policy with CAP_NET_ADMIN and tuntap, but no full root
policies.AllowNamespaceInsecure("implr-vpn"),
],
+
+ # Admission controller that permits non-privileged users to manage
+ # their namespaces without danger of hijacking important URLs.
+ admitomatic: admitomatic.Environment {
+ cfg+: {
+ proto: {
+ // Domains allowed in given namespaces. If a domain exists
+ // anywhere, ingresses will only be permitted to be created
+ // within namespaces in which it appears here. This works
+ // the same way for wildcards, if a wildcard exists in this
+ // list it blocks all unauthorized uses of that domain
+ // elsewhere.
+ //
+ // See //cluster/admitomatic for more information.
+ //
+ // Or, tl;dr:
+ //
+ // If you do a wildcard CNAME onto the k0 ingress, you
+ // should explicitly state *.your.name.com here.
+ //
+ // If you just want to protect your host from being
+ // hijacked by other cluster users, you should also state
+ // it here (either as a wildcard, or unary domains).
+ allow_domain: [
+ { namespace: "covid-formity", dns: "covid19.hackerspace.pl" },
+ { namespace: "covid-formity", dns: "covid.hackerspace.pl" },
+ { namespace: "covid-formity", dns: "www.covid.hackerspace.pl" },
+ { namespace: "devtools-prod", dns: "hackdoc.hackerspace.pl" },
+ { namespace: "devtools-prod", dns: "cs.hackerspace.pl" },
+ { namespace: "engelsystem-prod", dns: "engelsystem.hackerspace.pl" },
+ { namespace: "gerrit", dns: "gerrit.hackerspace.pl" },
+ { namespace: "gitea-prod", dns: "gitea.hackerspace.pl" },
+ { namespace: "hswaw-prod", dns: "*.hackerspace.pl" },
+ { namespace: "internet", dns: "internet.hackerspace.pl" },
+ { namespace: "matrix", dns: "matrix.hackerspace.pl" },
+ { namespace: "onlyoffice-prod", dns: "office.hackerspace.pl" },
+ { namespace: "redmine", dns: "issues.hackerspace.pl" },
+ { namespace: "speedtest", dns: "speedtest.hackerspace.pl" },
+ { namespace: "sso", dns: "sso.hackerspace.pl" },
+
+ { namespace: "ceph-waw3", dns: "ceph-waw3.hswaw.net" },
+ { namespace: "ceph-waw3", dns: "object.ceph-waw3.hswaw.net" },
+ { namespace: "monitoring-global-k0", dns: "*.hswaw.net" },
+ { namespace: "registry", dns: "*.hswaw.net" },
+
+ // q3k's legacy namespace (pre-prodvider)
+ { namespace: "q3k", dns: "*.q3k.org" },
+ { namespace: "personal-q3k", dns: "*.q3k.org" },
+ ],
+ },
+ },
+ },
},
}
diff --git a/cluster/kube/lib/admitomatic.libsonnet b/cluster/kube/lib/admitomatic.libsonnet
new file mode 100644
index 0000000..36ea5ef
--- /dev/null
+++ b/cluster/kube/lib/admitomatic.libsonnet
@@ -0,0 +1,94 @@
+// Deploys admitomatic, a validating admission webhook. It is used in
+// conjunction with Kubernetes' RBAC to provide a level of multitenancy to the
+// cluster, adding extra restrictions to resources created by non-administrative
+// users.
+//
+// For more information about admitomatic , see //cluster/admitomatic .
+//
+// As with every Kubernetes admission webhook, the Kubernetes control plane
+// (ie. apiserver) needs to be able to dial the deployed admitomatic service.
+// The authentication story for this is unfortunately quite sad and requires
+// the use of a pre-generated one-shot CA and certificate.
+//
+// .---- self-signed -.
+// v |
+// Admitomatic CA ----------' <-- caBundle used by apiserver,
+// | set in ValidatingWebhookConfiguration
+// v
+// Admitomatic Cert <-- admitomatic_tls_cert used by admitomatic
+//
+// This CA needs to be provisioned ahead of time by ourselves. In order to keep
+// things simple (as admitomatic being an admission webhook becomes a core
+// component of the k8s control plane), we generate this CA as plain text
+// secrets, and store them with secretstore in git. This is done via clustercfg.
+
+local kube = import "../../../kube/kube.libsonnet";
+local prototext = import "../../../kube/prototext.libsonnet";
+
+{
+ Environment: {
+ local env = self,
+ local cfg = env.cfg,
+
+ cfg:: {
+ namespace: "admitomatic",
+ image: "registry.k0.hswaw.net/q3k/admitomatic:1612618063-0b68e233116f733fb3ec9016c9d3b7decb86f192",
+
+ proto: {},
+ },
+
+ namespace: kube.Namespace(cfg.namespace),
+ local ns = self.namespace,
+
+ config: ns.Contain(kube.ConfigMap("admitomatic")) {
+ data: {
+ "config.pb.text": prototext.manifestProtoText(cfg.proto),
+ },
+ },
+
+ secret: ns.Contain(kube.Secret("admitomatic")) {
+ data_: {
+ "webhook.key": importstr "../../secrets/plain/admitomatic-webhook.key",
+ "webhook.crt": importstr "../../certs/admitomatic-webhook.cert",
+ },
+ },
+
+ daemonset: ns.Contain(kube.DaemonSet("admitomatic")) {
+ spec+: {
+ template+: {
+ spec+: {
+ containers_: {
+ default: kube.Container("default") {
+ image: cfg.image,
+ args: [
+ "/cluster/admitomatic/admitomatic",
+ "-admitomatic_config", "/admitomatic/config/config.pb.text",
+ "-admitomatic_listen", "0.0.0.0:8443",
+ "-admitomatic_tls_cert", "/admitomatic/secret/webhook.crt",
+ "-admitomatic_tls_key", "/admitomatic/secret/webhook.key",
+ // doesn't serve anything over gRPC.
+ "-hspki_disable"
+ ],
+ volumeMounts_: {
+ config: { mountPath: "/admitomatic/config" },
+ secret: { mountPath: "/admitomatic/secret" },
+ },
+ ports_: {
+ public: { containerPort: 8443 },
+ },
+ },
+ },
+ volumes_: {
+ config: kube.ConfigMapVolume(env.config),
+ secret: kube.SecretVolume(env.secret),
+ },
+ },
+ },
+ },
+ },
+
+ svc: ns.Contain(kube.Service("admitomatic")) {
+ target_pod:: env.daemonset.spec.template,
+ },
+ },
+}