smsgw: productionize, implement kube/mirko

This productionizes smsgw.

We also add some jsonnet machinery to provide a unified service for Go
micro/mirkoservices.

This machinery provides all the nice stuff:
 - a deployment
 - a service for all your types of pots
 - TLS certificates for HSPKI

We also update and test hspki for a new name scheme.

Change-Id: I292d00f858144903cbc8fe0c1c26eb1180d636bc
diff --git a/hswaw/kube/hswaw.jsonnet b/hswaw/kube/hswaw.jsonnet
new file mode 100644
index 0000000..d8a5131
--- /dev/null
+++ b/hswaw/kube/hswaw.jsonnet
@@ -0,0 +1,96 @@
+local mirko = import "../../kube/mirko.libsonnet";
+local kube = import "../../kube/kube.libsonnet";
+
+{
+    hswaw(name):: mirko.Environment(name) {
+        local env = self,
+        local cfg = self.cfg,
+
+        cfg+: {
+            smsgw: {
+                secret: {
+                    twilio_token: error "twilio_token must be set",
+                },
+                image: "registry.k0.hswaw.net/q3k/smsgs:1570049853-05c5b491c45de6d960979d4aee8635768f3178e9",
+                webhookFQDN: error "webhookFQDN must be set",
+            },
+        },
+
+        components: {
+            smsgw: mirko.Component(env, "smsgw") {
+                local smsgw = self,
+                cfg+: {
+                    image: cfg.smsgw.image,
+                    container: smsgw.GoContainer("main", "/smsgw/smsgw") {
+                        env_: {
+                            TWILIO_TOKEN: kube.SecretKeyRef(smsgw.secret, "twilio_token"),
+                        },
+                        command+: [
+                            "-twilio_friendly_phone", "48732168371",
+                            "-twilio_sid", "AC806ed4bf4b6c80c8f8ea686379b69518",
+                            "-twilio_token", "$(TWILIO_TOKEN)",
+                            "-webhook_listen", "0.0.0.0:5000",
+                            "-webhook_public", "https://%s/" % [ env.cfg.smsgw.webhookFQDN ],
+                        ],
+                    },
+                    ports+: {
+                        publicHTTP: {
+                            webhook: {
+                                port: 5000,
+                                dns: env.cfg.smsgw.webhookFQDN,
+                            }
+                        },
+                    },
+                },
+
+                secret: kube.Secret("smsgw") {
+                    metadata+: smsgw.metadata,
+                    data: env.cfg.smsgw.secret,
+                },
+
+                // Temporary machinery to access gRPC from outsite.
+                // In the future, this will be handled by a proxy/API gateway.
+                // For now, we need this running.
+                // TODO(q3k): remove this when we have an API GW or proxy.
+                stopgap: {
+                    rpcLB: kube.Service("smsgw-tcp-rpc") {
+                        metadata+: smsgw.metadata,
+                        target_pod: smsgw.deployment.spec.template,
+                        spec+: {
+                            type: "LoadBalancer",
+                            ports: [
+                                { name: "grpc-external", port: 443, targetPort: 4200 },
+                            ],
+                        },
+                    },
+
+                    rpcCertificate: kube.Certificate("smsgw-tcp-rpc-consumer") {
+                        metadata+: smsgw.metadata,
+                        spec: {
+                            secretName: "smsgw-tcp-rpc-consumer",
+                            duration: "35040h0m0s", // 4 years
+                            issuerRef: {
+                                // Contract with cluster/lib/pki.libsonnet.
+                                // Copied over.
+                                name: "pki-ca",
+                                kind: "ClusterIssuer",
+                            },
+                            commonName: "kasownik.external.hswaw.net",
+                        },
+                    },
+                }
+            },
+        },
+    },
+
+    prod: self.hswaw("hswaw-prod") {
+        cfg+: {
+            smsgw+: {
+                secret+: {
+                    twilio_token: std.base64(std.split(importstr "secrets/plain/prod-twilio-token", "\n")[0]),
+                },
+                webhookFQDN: "smsgw-webhook-prod.hswaw.net",
+            }
+        },
+    },
+}
diff --git a/hswaw/kube/secrets/.gitignore b/hswaw/kube/secrets/.gitignore
new file mode 100644
index 0000000..b9bca01
--- /dev/null
+++ b/hswaw/kube/secrets/.gitignore
@@ -0,0 +1 @@
+plain
diff --git a/hswaw/kube/secrets/cipher/prod-twilio-token b/hswaw/kube/secrets/cipher/prod-twilio-token
new file mode 100644
index 0000000..12b5749
--- /dev/null
+++ b/hswaw/kube/secrets/cipher/prod-twilio-token
@@ -0,0 +1,40 @@
+-----BEGIN PGP MESSAGE-----
+
+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
+jDM7tUYE8kNa/hBa1S7vX11NJLjRoE+P0d1p
+=WIU6
+-----END PGP MESSAGE-----
diff --git a/hswaw/smsgw/BUILD.bazel b/hswaw/smsgw/BUILD.bazel
index 35b36f1..0e91141 100644
--- a/hswaw/smsgw/BUILD.bazel
+++ b/hswaw/smsgw/BUILD.bazel
@@ -1,3 +1,4 @@
+load("@io_bazel_rules_docker//container:container.bzl", "container_image", "container_layer", "container_push")
 load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", "go_test")
 
 go_library(
@@ -29,3 +30,28 @@
     srcs = ["dispatcher_test.go"],
     embed = [":go_default_library"],
 )
+
+container_layer(
+    name = "layer_bin",
+    files = [
+        ":smsgw",
+    ],
+    directory = "/smsgw/",
+)
+
+container_image(
+    name = "runtime",
+    base = "@prodimage-bionic//image",
+    layers = [
+        ":layer_bin",
+    ],
+)
+
+container_push(
+    name = "push",
+    image = ":runtime",
+    format = "Docker",
+    registry = "registry.k0.hswaw.net",
+    repository = "q3k/smsgs",
+    tag = "{BUILD_TIMESTAMP}-{STABLE_GIT_COMMIT}",
+)
diff --git a/hswaw/smsgw/main.go b/hswaw/smsgw/main.go
index a0a6a07..3095c00 100644
--- a/hswaw/smsgw/main.go
+++ b/hswaw/smsgw/main.go
@@ -76,7 +76,7 @@
 			glog.Infof("Webhook not yet ready, currently %s %q", pn.SMSMethod, pn.SMSURL)
 			time.Sleep(5 * time.Second)
 		}
-		glog.Infof("Webhook verifier")
+		glog.Infof("Webhook verified")
 	} else {
 		glog.Infof("Webhook up to date")
 	}