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/go/pki/grpc.go b/go/pki/grpc.go
index 6d8f173..1720ad8 100644
--- a/go/pki/grpc.go
+++ b/go/pki/grpc.go
@@ -36,6 +36,7 @@
 	flagCAPath          string
 	flagCertificatePath string
 	flagKeyPath         string
+	flagPKICluster      string
 	flagPKIRealm        string
 	flagPKIDisable      bool
 
@@ -53,7 +54,8 @@
 	flag.StringVar(&flagCAPath, "hspki_tls_ca_path", "pki/ca.pem", "Path to PKI CA certificate")
 	flag.StringVar(&flagCertificatePath, "hspki_tls_certificate_path", "pki/service.pem", "Path to PKI service certificate")
 	flag.StringVar(&flagKeyPath, "hspki_tls_key_path", "pki/service-key.pem", "Path to PKI service private key")
-	flag.StringVar(&flagPKIRealm, "hspki_realm", "svc.cluster.local", "PKI realm")
+	flag.StringVar(&flagPKICluster, "hspki_cluster", "local.hswaw.net", "FQDN of cluster on which this service runs")
+	flag.StringVar(&flagPKIRealm, "hspki_realm", "hswaw.net", "Cluster realm (top level from which we accept foreign cluster certs)")
 	flag.BoolVar(&flagPKIDisable, "hspki_disable", false, "Disable PKI entirely (insecure!)")
 }
 
@@ -81,14 +83,39 @@
 	if !strings.HasSuffix(name, "."+flagPKIRealm) {
 		return nil, fmt.Errorf("invalid realm")
 	}
-	service := strings.TrimSuffix(name, "."+flagPKIRealm)
-	parts := strings.Split(service, ".")
-	if len(parts) != 2 {
-		return nil, fmt.Errorf("invalid job/principal format")
+
+	inRealm := strings.TrimSuffix(name, "."+flagPKIRealm)
+
+	special := []string{"person", "external"}
+
+	for _, s := range special {
+		// Special case for people running jobs from workstations, or for non-cluster services.
+		if strings.HasSuffix(inRealm, "."+s) {
+			asPerson := strings.TrimSuffix(inRealm, "."+s)
+			parts := strings.Split(asPerson, ".")
+			if len(parts) != 1 {
+				return nil, fmt.Errorf("invalid person fqdn")
+			}
+			return &ClientInfo{
+				Cluster:   fmt.Sprintf("%s.%s", s, flagPKIRealm),
+				Principal: parts[0],
+				Job:       "",
+			}, nil
+		}
 	}
+
+	parts := strings.Split(inRealm, ".")
+	if len(parts) != 4 {
+		return nil, fmt.Errorf("invalid job/principal format for in-cluster")
+	}
+	if parts[2] != "svc" {
+		return nil, fmt.Errorf("can only refer to services within cluster")
+	}
+	clusterShort := parts[3]
+
 	return &ClientInfo{
-		Realm:     flagPKIRealm,
-		Principal: parts[1],
+		Cluster:   fmt.Sprintf("%s.%s", clusterShort, flagPKIRealm),
+		Principal: fmt.Sprintf("%s.svc", parts[1]),
 		Job:       parts[0],
 	}, nil
 }
@@ -137,15 +164,24 @@
 // ClientInfo contains information about the HSPKI authentication data of the
 // gRPC client that has made the request.
 type ClientInfo struct {
-	Realm     string
+	Cluster   string
 	Principal string
 	Job       string
 }
 
 // String returns a human-readable representation of the ClientInfo in the
-// form "job=foo, principal=bar, realm=baz".
+// form "job=foo, principal=bar.svc, cluster=baz.hswaw.net".
 func (c *ClientInfo) String() string {
-	return fmt.Sprintf("job=%q, principal=%q, realm=%q", c.Job, c.Principal, c.Realm)
+	return fmt.Sprintf("job=%q, principal=%q, cluster=%q", c.Job, c.Principal, c.Cluster)
+}
+
+// Person returns a reference to a person's ID if the ClientInfo describes a person.
+// Otherwise, it returns an empty string.
+func (c *ClientInfo) Person() string {
+	if c.Cluster != fmt.Sprintf("person.%s", flagPKIRealm) {
+		return ""
+	}
+	return c.Principal
 }
 
 // ClientInfoFromContext returns ClientInfo from a gRPC service context.