*: developer machine HSPKI credentials
In addition to k8s certificates, prodaccess now issues HSPKI
certificates, with DN=$username.sso.hswaw.net. These are installed into
XDG_CONFIG_HOME (or os equiv).
//go/pki will now automatically attempt to load these certificates. This
means you can now run any pki-dependant tool with -hspki_disable, and
with automatic mTLS!
Change-Id: I5b28e193e7c968d621bab0d42aabd6f0510fed6d
diff --git a/go/pki/BUILD.bazel b/go/pki/BUILD.bazel
index 5bc7522..f2eae41 100644
--- a/go/pki/BUILD.bazel
+++ b/go/pki/BUILD.bazel
@@ -2,7 +2,10 @@
go_library(
name = "go_default_library",
- srcs = ["grpc.go"],
+ srcs = [
+ "grpc.go",
+ "locate.go",
+ ],
importpath = "code.hackerspace.pl/hscloud/go/pki",
visibility = ["//visibility:public"],
deps = [
diff --git a/go/pki/grpc.go b/go/pki/grpc.go
index 1720ad8..313f4a9 100644
--- a/go/pki/grpc.go
+++ b/go/pki/grpc.go
@@ -20,7 +20,6 @@
"crypto/x509"
"flag"
"fmt"
- "io/ioutil"
"strings"
"github.com/golang/glog"
@@ -210,18 +209,19 @@
return []grpc.ServerOption{}
}
- serverCert, err := tls.LoadX509KeyPair(flagCertificatePath, flagKeyPath)
+ loc, err := loadCredentials()
+ if err != nil {
+ glog.Exitf("WithServerHSPKI: loadCredentials: %v", err)
+ }
+
+ serverCert, err := tls.X509KeyPair(loc.cert, loc.key)
if err != nil {
glog.Exitf("WithServerHSPKI: cannot load service certificate/key: %v", err)
}
certPool := x509.NewCertPool()
- ca, err := ioutil.ReadFile(flagCAPath)
- if err != nil {
- glog.Exitf("WithServerHSPKI: cannot load CA certificate: %v", err)
- }
- if ok := certPool.AppendCertsFromPEM(ca); !ok {
- glog.Exitf("WithServerHSPKI: cannot use CA certificate: %v", err)
+ if ok := certPool.AppendCertsFromPEM(loc.ca); !ok {
+ glog.Exitf("WithServerHSPKI: cannot use CA certificate")
}
creds := grpc.Creds(credentials.NewTLS(&tls.Config{
@@ -243,16 +243,17 @@
return grpc.WithInsecure()
}
- certPool := x509.NewCertPool()
- ca, err := ioutil.ReadFile(flagCAPath)
+ loc, err := loadCredentials()
if err != nil {
- glog.Exitf("WithClientHSPKI: cannot load CA certificate: %v", err)
- }
- if ok := certPool.AppendCertsFromPEM(ca); !ok {
- glog.Exitf("WithClientHSPKI: cannot use CA certificate: %v", err)
+ glog.Exitf("WithServerHSPKI: loadCredentials: %v", err)
}
- clientCert, err := tls.LoadX509KeyPair(flagCertificatePath, flagKeyPath)
+ certPool := x509.NewCertPool()
+ if ok := certPool.AppendCertsFromPEM(loc.ca); !ok {
+ glog.Exitf("WithServerHSPKI: cannot use CA certificate")
+ }
+
+ clientCert, err := tls.X509KeyPair(loc.cert, loc.key)
if err != nil {
glog.Exitf("WithClientHSPKI: cannot load service certificate/key: %v", err)
}
diff --git a/go/pki/locate.go b/go/pki/locate.go
new file mode 100644
index 0000000..e48e013
--- /dev/null
+++ b/go/pki/locate.go
@@ -0,0 +1,88 @@
+package pki
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+
+ "github.com/golang/glog"
+)
+
+// DeveloperCredentialsLocation returns the path containing HSPKI credentials
+// on developer machines. These are provisioned by //cluster/prodaccess, and
+// are used if available.
+func DeveloperCredentialsLocation() (string, error) {
+ cfgDir, err := os.UserConfigDir()
+ if err != nil {
+ glog.Exitf("UserConfigDir: %w", err)
+ }
+
+ return fmt.Sprintf("%s/hspki", cfgDir), nil
+}
+
+type creds struct {
+ ca []byte
+ cert []byte
+ key []byte
+}
+
+func loadDeveloperCredentials() (*creds, error) {
+ path, err := DeveloperCredentialsLocation()
+ if err != nil {
+ return nil, fmt.Errorf("DeveloperCredentialsLocation: %w")
+ }
+
+ c := creds{}
+ for _, el := range []struct {
+ target *[]byte
+ path string
+ }{
+ {&c.ca, path + "/" + "ca.crt"},
+ {&c.cert, path + "/" + "tls.crt"},
+ {&c.key, path + "/" + "tls.key"},
+ } {
+ data, err := ioutil.ReadFile(el.path)
+ if err != nil {
+ return nil, fmt.Errorf("ReadFile(%q): %w", el.path, err)
+ }
+ *el.target = data
+ }
+
+ return &c, nil
+}
+
+func loadFlagCredentials() (*creds, error) {
+ c := creds{}
+ for _, el := range []struct {
+ target *[]byte
+ path string
+ }{
+ {&c.ca, flagCAPath},
+ {&c.cert, flagCertificatePath},
+ {&c.key, flagKeyPath},
+ } {
+ data, err := ioutil.ReadFile(el.path)
+ if err != nil {
+ return nil, fmt.Errorf("ReadFile(%q): %w", el.path, err)
+ }
+ *el.target = data
+ }
+
+ return &c, nil
+}
+
+func loadCredentials() (*creds, error) {
+ dev, err := loadDeveloperCredentials()
+ if err == nil {
+ return dev, nil
+ }
+ glog.Warningf("Could not load developer PKI credentials: %v", err)
+
+ fl, err := loadFlagCredentials()
+ if err == nil {
+ return fl, err
+ }
+ glog.Warningf("Could not load flag-defined PKI credentials: %v", err)
+
+ return nil, fmt.Errorf("could not load any credentials")
+}