Add QR code support to `nebula-cert` (#297)
This commit is contained in:
parent
454bc8a6bb
commit
d4b81f9b8d
|
@ -11,6 +11,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/skip2/go-qrcode"
|
||||||
"github.com/slackhq/nebula/cert"
|
"github.com/slackhq/nebula/cert"
|
||||||
"golang.org/x/crypto/ed25519"
|
"golang.org/x/crypto/ed25519"
|
||||||
)
|
)
|
||||||
|
@ -21,6 +22,7 @@ type caFlags struct {
|
||||||
duration *time.Duration
|
duration *time.Duration
|
||||||
outKeyPath *string
|
outKeyPath *string
|
||||||
outCertPath *string
|
outCertPath *string
|
||||||
|
outQRPath *string
|
||||||
groups *string
|
groups *string
|
||||||
ips *string
|
ips *string
|
||||||
subnets *string
|
subnets *string
|
||||||
|
@ -33,6 +35,7 @@ func newCaFlags() *caFlags {
|
||||||
cf.duration = cf.set.Duration("duration", time.Duration(time.Hour*8760), "Optional: amount of time the certificate should be valid for. Valid time units are seconds: \"s\", minutes: \"m\", hours: \"h\"")
|
cf.duration = cf.set.Duration("duration", time.Duration(time.Hour*8760), "Optional: amount of time the certificate should be valid for. Valid time units are seconds: \"s\", minutes: \"m\", hours: \"h\"")
|
||||||
cf.outKeyPath = cf.set.String("out-key", "ca.key", "Optional: path to write the private key to")
|
cf.outKeyPath = cf.set.String("out-key", "ca.key", "Optional: path to write the private key to")
|
||||||
cf.outCertPath = cf.set.String("out-crt", "ca.crt", "Optional: path to write the certificate to")
|
cf.outCertPath = cf.set.String("out-crt", "ca.crt", "Optional: path to write the certificate to")
|
||||||
|
cf.outQRPath = cf.set.String("out-qr", "", "Optional: output a qr code image (png) of the certificate")
|
||||||
cf.groups = cf.set.String("groups", "", "Optional: comma separated list of groups. This will limit which groups subordinate certs can use")
|
cf.groups = cf.set.String("groups", "", "Optional: comma separated list of groups. This will limit which groups subordinate certs can use")
|
||||||
cf.ips = cf.set.String("ips", "", "Optional: comma separated list of ip and network in CIDR notation. This will limit which ip addresses and networks subordinate certs can use")
|
cf.ips = cf.set.String("ips", "", "Optional: comma separated list of ip and network in CIDR notation. This will limit which ip addresses and networks subordinate certs can use")
|
||||||
cf.subnets = cf.set.String("subnets", "", "Optional: comma separated list of ip and network in CIDR notation. This will limit which subnet addresses and networks subordinate certs can use")
|
cf.subnets = cf.set.String("subnets", "", "Optional: comma separated list of ip and network in CIDR notation. This will limit which subnet addresses and networks subordinate certs can use")
|
||||||
|
@ -146,6 +149,18 @@ func ca(args []string, out io.Writer, errOut io.Writer) error {
|
||||||
return fmt.Errorf("error while writing out-crt: %s", err)
|
return fmt.Errorf("error while writing out-crt: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if *cf.outQRPath != "" {
|
||||||
|
b, err = qrcode.Encode(string(b), qrcode.Medium, -5)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error while generating qr code: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = ioutil.WriteFile(*cf.outQRPath, b, 0600)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error while writing out-qr: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,8 @@ func Test_caHelp(t *testing.T) {
|
||||||
" \tOptional: path to write the certificate to (default \"ca.crt\")\n"+
|
" \tOptional: path to write the certificate to (default \"ca.crt\")\n"+
|
||||||
" -out-key string\n"+
|
" -out-key string\n"+
|
||||||
" \tOptional: path to write the private key to (default \"ca.key\")\n"+
|
" \tOptional: path to write the private key to (default \"ca.key\")\n"+
|
||||||
|
" -out-qr string\n"+
|
||||||
|
" \tOptional: output a qr code image (png) of the certificate\n"+
|
||||||
" -subnets string\n"+
|
" -subnets string\n"+
|
||||||
" \tOptional: comma separated list of ip and network in CIDR notation. This will limit which subnet addresses and networks subordinate certs can use\n",
|
" \tOptional: comma separated list of ip and network in CIDR notation. This will limit which subnet addresses and networks subordinate certs can use\n",
|
||||||
ob.String(),
|
ob.String(),
|
||||||
|
|
|
@ -9,19 +9,22 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/skip2/go-qrcode"
|
||||||
"github.com/slackhq/nebula/cert"
|
"github.com/slackhq/nebula/cert"
|
||||||
)
|
)
|
||||||
|
|
||||||
type printFlags struct {
|
type printFlags struct {
|
||||||
set *flag.FlagSet
|
set *flag.FlagSet
|
||||||
json *bool
|
json *bool
|
||||||
path *string
|
outQRPath *string
|
||||||
|
path *string
|
||||||
}
|
}
|
||||||
|
|
||||||
func newPrintFlags() *printFlags {
|
func newPrintFlags() *printFlags {
|
||||||
pf := printFlags{set: flag.NewFlagSet("print", flag.ContinueOnError)}
|
pf := printFlags{set: flag.NewFlagSet("print", flag.ContinueOnError)}
|
||||||
pf.set.Usage = func() {}
|
pf.set.Usage = func() {}
|
||||||
pf.json = pf.set.Bool("json", false, "Optional: outputs certificates in json format")
|
pf.json = pf.set.Bool("json", false, "Optional: outputs certificates in json format")
|
||||||
|
pf.outQRPath = pf.set.String("out-qr", "", "Optional: output a qr code image (png) of the certificate")
|
||||||
pf.path = pf.set.String("path", "", "Required: path to the certificate")
|
pf.path = pf.set.String("path", "", "Required: path to the certificate")
|
||||||
|
|
||||||
return &pf
|
return &pf
|
||||||
|
@ -44,6 +47,8 @@ func printCert(args []string, out io.Writer, errOut io.Writer) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
var c *cert.NebulaCertificate
|
var c *cert.NebulaCertificate
|
||||||
|
var qrBytes []byte
|
||||||
|
part := 0
|
||||||
|
|
||||||
for {
|
for {
|
||||||
c, rawCert, err = cert.UnmarshalNebulaCertificateFromPEM(rawCert)
|
c, rawCert, err = cert.UnmarshalNebulaCertificateFromPEM(rawCert)
|
||||||
|
@ -61,9 +66,31 @@ func printCert(args []string, out io.Writer, errOut io.Writer) error {
|
||||||
out.Write([]byte("\n"))
|
out.Write([]byte("\n"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if *pf.outQRPath != "" {
|
||||||
|
b, err := c.MarshalToPEM()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error while marshalling cert to PEM: %s", err)
|
||||||
|
}
|
||||||
|
qrBytes = append(qrBytes, b...)
|
||||||
|
}
|
||||||
|
|
||||||
if rawCert == nil || len(rawCert) == 0 || strings.TrimSpace(string(rawCert)) == "" {
|
if rawCert == nil || len(rawCert) == 0 || strings.TrimSpace(string(rawCert)) == "" {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
part++
|
||||||
|
}
|
||||||
|
|
||||||
|
if *pf.outQRPath != "" {
|
||||||
|
b, err := qrcode.Encode(string(qrBytes), qrcode.Medium, -5)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error while generating qr code: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = ioutil.WriteFile(*pf.outQRPath, b, 0600)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error while writing out-qr: %s", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -23,6 +23,8 @@ func Test_printHelp(t *testing.T) {
|
||||||
"Usage of "+os.Args[0]+" print <flags>: prints details about a certificate\n"+
|
"Usage of "+os.Args[0]+" print <flags>: prints details about a certificate\n"+
|
||||||
" -json\n"+
|
" -json\n"+
|
||||||
" \tOptional: outputs certificates in json format\n"+
|
" \tOptional: outputs certificates in json format\n"+
|
||||||
|
" -out-qr string\n"+
|
||||||
|
" \tOptional: output a qr code image (png) of the certificate\n"+
|
||||||
" -path string\n"+
|
" -path string\n"+
|
||||||
" \tRequired: path to the certificate\n",
|
" \tRequired: path to the certificate\n",
|
||||||
ob.String(),
|
ob.String(),
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/skip2/go-qrcode"
|
||||||
"github.com/slackhq/nebula/cert"
|
"github.com/slackhq/nebula/cert"
|
||||||
"golang.org/x/crypto/curve25519"
|
"golang.org/x/crypto/curve25519"
|
||||||
)
|
)
|
||||||
|
@ -25,6 +26,7 @@ type signFlags struct {
|
||||||
inPubPath *string
|
inPubPath *string
|
||||||
outKeyPath *string
|
outKeyPath *string
|
||||||
outCertPath *string
|
outCertPath *string
|
||||||
|
outQRPath *string
|
||||||
groups *string
|
groups *string
|
||||||
subnets *string
|
subnets *string
|
||||||
}
|
}
|
||||||
|
@ -40,6 +42,7 @@ func newSignFlags() *signFlags {
|
||||||
sf.inPubPath = sf.set.String("in-pub", "", "Optional (if out-key not set): path to read a previously generated public key")
|
sf.inPubPath = sf.set.String("in-pub", "", "Optional (if out-key not set): path to read a previously generated public key")
|
||||||
sf.outKeyPath = sf.set.String("out-key", "", "Optional (if in-pub not set): path to write the private key to")
|
sf.outKeyPath = sf.set.String("out-key", "", "Optional (if in-pub not set): path to write the private key to")
|
||||||
sf.outCertPath = sf.set.String("out-crt", "", "Optional: path to write the certificate to")
|
sf.outCertPath = sf.set.String("out-crt", "", "Optional: path to write the certificate to")
|
||||||
|
sf.outQRPath = sf.set.String("out-qr", "", "Optional: output a qr code image (png) of the certificate")
|
||||||
sf.groups = sf.set.String("groups", "", "Optional: comma separated list of groups")
|
sf.groups = sf.set.String("groups", "", "Optional: comma separated list of groups")
|
||||||
sf.subnets = sf.set.String("subnets", "", "Optional: comma seperated list of subnet this cert can serve for")
|
sf.subnets = sf.set.String("subnets", "", "Optional: comma seperated list of subnet this cert can serve for")
|
||||||
return &sf
|
return &sf
|
||||||
|
@ -203,6 +206,18 @@ func signCert(args []string, out io.Writer, errOut io.Writer) error {
|
||||||
return fmt.Errorf("error while writing out-crt: %s", err)
|
return fmt.Errorf("error while writing out-crt: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if *sf.outQRPath != "" {
|
||||||
|
b, err = qrcode.Encode(string(b), qrcode.Medium, -5)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error while generating qr code: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = ioutil.WriteFile(*sf.outQRPath, b, 0600)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error while writing out-qr: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,8 @@ func Test_signHelp(t *testing.T) {
|
||||||
" \tOptional: path to write the certificate to\n"+
|
" \tOptional: path to write the certificate to\n"+
|
||||||
" -out-key string\n"+
|
" -out-key string\n"+
|
||||||
" \tOptional (if in-pub not set): path to write the private key to\n"+
|
" \tOptional (if in-pub not set): path to write the private key to\n"+
|
||||||
|
" -out-qr string\n"+
|
||||||
|
" \tOptional: output a qr code image (png) of the certificate\n"+
|
||||||
" -subnets string\n"+
|
" -subnets string\n"+
|
||||||
" \tOptional: comma seperated list of subnet this cert can serve for\n",
|
" \tOptional: comma seperated list of subnet this cert can serve for\n",
|
||||||
ob.String(),
|
ob.String(),
|
||||||
|
@ -286,5 +288,4 @@ func Test_signCert(t *testing.T) {
|
||||||
assert.EqualError(t, signCert(args, ob, eb), "refusing to overwrite existing cert: "+crtF.Name())
|
assert.EqualError(t, signCert(args, ob, eb), "refusing to overwrite existing cert: "+crtF.Name())
|
||||||
assert.Empty(t, ob.String())
|
assert.Empty(t, ob.String())
|
||||||
assert.Empty(t, eb.String())
|
assert.Empty(t, eb.String())
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
1
go.mod
1
go.mod
|
@ -21,6 +21,7 @@ require (
|
||||||
github.com/prometheus/procfs v0.0.8 // indirect
|
github.com/prometheus/procfs v0.0.8 // indirect
|
||||||
github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563
|
github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563
|
||||||
github.com/sirupsen/logrus v1.4.2
|
github.com/sirupsen/logrus v1.4.2
|
||||||
|
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
|
||||||
github.com/songgao/water v0.0.0-20190725173103-fd331bda3f4b
|
github.com/songgao/water v0.0.0-20190725173103-fd331bda3f4b
|
||||||
github.com/stretchr/testify v1.6.1
|
github.com/stretchr/testify v1.6.1
|
||||||
github.com/vishvananda/netlink v1.0.1-0.20190522153524-00009fb8606a
|
github.com/vishvananda/netlink v1.0.1-0.20190522153524-00009fb8606a
|
||||||
|
|
2
go.sum
2
go.sum
|
@ -98,6 +98,8 @@ github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqn
|
||||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
|
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
|
||||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||||
|
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
|
||||||
|
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
|
||||||
github.com/songgao/water v0.0.0-20190725173103-fd331bda3f4b h1:+y4hCMc/WKsDbAPsOQZgBSaSZ26uh2afyaWeVg/3s/c=
|
github.com/songgao/water v0.0.0-20190725173103-fd331bda3f4b h1:+y4hCMc/WKsDbAPsOQZgBSaSZ26uh2afyaWeVg/3s/c=
|
||||||
github.com/songgao/water v0.0.0-20190725173103-fd331bda3f4b/go.mod h1:P5HUIBuIWKbyjl083/loAegFkfbFNx5i2qEP4CNbm7E=
|
github.com/songgao/water v0.0.0-20190725173103-fd331bda3f4b/go.mod h1:P5HUIBuIWKbyjl083/loAegFkfbFNx5i2qEP4CNbm7E=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
|
Loading…
Reference in New Issue