ca.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. package main
  2. import (
  3. "crypto/rand"
  4. "flag"
  5. "fmt"
  6. "io"
  7. "io/ioutil"
  8. "os"
  9. "strings"
  10. "time"
  11. "golang.org/x/crypto/ed25519"
  12. "github.com/slackhq/nebula/cert"
  13. )
  14. type caFlags struct {
  15. set *flag.FlagSet
  16. name *string
  17. duration *time.Duration
  18. outKeyPath *string
  19. outCertPath *string
  20. groups *string
  21. }
  22. func newCaFlags() *caFlags {
  23. cf := caFlags{set: flag.NewFlagSet("ca", flag.ContinueOnError)}
  24. cf.set.Usage = func() {}
  25. cf.name = cf.set.String("name", "", "Required: name of the certificate authority")
  26. 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\"")
  27. cf.outKeyPath = cf.set.String("out-key", "ca.key", "Optional: path to write the private key to")
  28. cf.outCertPath = cf.set.String("out-crt", "ca.crt", "Optional: path to write the certificate to")
  29. cf.groups = cf.set.String("groups", "", "Optional: comma separated list of groups. This will limit which groups subordinate certs can use")
  30. return &cf
  31. }
  32. func ca(args []string, out io.Writer, errOut io.Writer) error {
  33. cf := newCaFlags()
  34. err := cf.set.Parse(args)
  35. if err != nil {
  36. return err
  37. }
  38. if err := mustFlagString("name", cf.name); err != nil {
  39. return err
  40. }
  41. if err := mustFlagString("out-key", cf.outKeyPath); err != nil {
  42. return err
  43. }
  44. if err := mustFlagString("out-crt", cf.outCertPath); err != nil {
  45. return err
  46. }
  47. if *cf.duration <= 0 {
  48. return &helpError{"-duration must be greater than 0"}
  49. }
  50. groups := []string{}
  51. if *cf.groups != "" {
  52. for _, rg := range strings.Split(*cf.groups, ",") {
  53. g := strings.TrimSpace(rg)
  54. if g != "" {
  55. groups = append(groups, g)
  56. }
  57. }
  58. }
  59. pub, rawPriv, err := ed25519.GenerateKey(rand.Reader)
  60. if err != nil {
  61. return fmt.Errorf("error while generating ed25519 keys: %s", err)
  62. }
  63. nc := cert.NebulaCertificate{
  64. Details: cert.NebulaCertificateDetails{
  65. Name: *cf.name,
  66. Groups: groups,
  67. NotBefore: time.Now(),
  68. NotAfter: time.Now().Add(*cf.duration),
  69. PublicKey: pub,
  70. IsCA: true,
  71. },
  72. }
  73. if _, err := os.Stat(*cf.outKeyPath); err == nil {
  74. return fmt.Errorf("refusing to overwrite existing CA key: %s", *cf.outKeyPath)
  75. }
  76. if _, err := os.Stat(*cf.outCertPath); err == nil {
  77. return fmt.Errorf("refusing to overwrite existing CA cert: %s", *cf.outCertPath)
  78. }
  79. err = nc.Sign(rawPriv)
  80. if err != nil {
  81. return fmt.Errorf("error while signing: %s", err)
  82. }
  83. err = ioutil.WriteFile(*cf.outKeyPath, cert.MarshalEd25519PrivateKey(rawPriv), 0600)
  84. if err != nil {
  85. return fmt.Errorf("error while writing out-key: %s", err)
  86. }
  87. b, err := nc.MarshalToPEM()
  88. if err != nil {
  89. return fmt.Errorf("error while marshalling certificate: %s", err)
  90. }
  91. err = ioutil.WriteFile(*cf.outCertPath, b, 0600)
  92. if err != nil {
  93. return fmt.Errorf("error while writing out-crt: %s", err)
  94. }
  95. return nil
  96. }
  97. func caSummary() string {
  98. return "ca <flags>: create a self signed certificate authority"
  99. }
  100. func caHelp(out io.Writer) {
  101. cf := newCaFlags()
  102. out.Write([]byte("Usage of " + os.Args[0] + " " + caSummary() + "\n"))
  103. cf.set.SetOutput(out)
  104. cf.set.PrintDefaults()
  105. }