github.com/grailbio/base@v0.0.11/cmd/grail-role/main.go (about) 1 // The following enables go generate to generate the doc.go file. 2 //go:generate go run v.io/x/lib/cmdline/gendoc "--build-cmd=go install" --copyright-notice= . -help 3 4 package main 5 6 import ( 7 "bytes" 8 "encoding/base64" 9 "fmt" 10 "time" 11 12 _ "github.com/grailbio/base/cmdutil/interactive" 13 "github.com/grailbio/base/security/ticket" 14 _ "github.com/grailbio/v23/factories/grail" // Needed to initialize v23 15 "v.io/v23" 16 "v.io/v23/context" 17 "v.io/v23/security" 18 "v.io/v23/vom" 19 "v.io/x/lib/cmdline" 20 "v.io/x/lib/vlog" 21 libsecurity "v.io/x/ref/lib/security" 22 "v.io/x/ref/lib/v23cmd" 23 ) 24 25 const blessingSuffix = "_role" 26 27 var ( 28 durationFlag time.Duration 29 timeoutFlag time.Duration 30 ) 31 32 func newCmdRoot() *cmdline.Command { 33 cmd := &cmdline.Command{ 34 Runner: v23cmd.RunnerFunc(run), 35 Name: "role", 36 Short: "Creates credentials for a role account", 37 Long: ` 38 Command role creates Vanadium principals for a Vanadium role account. This is 39 accomplished by fetching a VanadiumTicket from the ticket-server. The 40 ticket-server will bless the principal presented by the client so 41 the blessing presented to the ticket-server is required to have a ':_role' 42 prefix to prevent the accidental reuse of the original private key of the 43 client. 44 45 Example: 46 47 grail role tickets/roles/lims-server /tmp/lims-server 48 `, 49 ArgsName: "<ticket> <directory>", 50 } 51 cmd.Flags.DurationVar(&durationFlag, "duration", 1*time.Hour, "Duration for the blessing.") 52 cmd.Flags.DurationVar(&timeoutFlag, "timeout", 10*time.Second, "The timeout of the requests to the server.") 53 return cmd 54 } 55 56 func run(ctx *context.T, env *cmdline.Env, args []string) error { 57 if len(args) != 2 { 58 return fmt.Errorf("Exactly two arguments are required: <ticket> <directory>") 59 } 60 ticketPath, dir := args[0], args[1] 61 62 principal, err := libsecurity.CreatePersistentPrincipal(dir, nil) 63 if err != nil { 64 return err 65 } 66 67 name, err := bless(ctx, principal, blessingSuffix) 68 if err != nil { 69 return err 70 } 71 72 if err := principal.BlessingStore().SetDefault(name); err != nil { 73 return err 74 } 75 if _, err := principal.BlessingStore().Set(name, security.AllPrincipals); err != nil { 76 return err 77 } 78 if err := security.AddToRoots(principal, name); err != nil { 79 return err 80 } 81 82 vlog.Infof("\n%s", principal.BlessingStore().DebugString()) 83 84 roleCtx, err := v23.WithPrincipal(ctx, principal) 85 if err != nil { 86 return err 87 } 88 89 client := ticket.TicketServiceClient(ticketPath) 90 _, cancel := context.WithTimeout(roleCtx, timeoutFlag) 91 defer cancel() 92 93 t, err := client.Get(roleCtx) 94 if err != nil { 95 return err 96 } 97 98 vlog.VI(1).Infof("%#v\n", t) 99 100 vanadiumTicket, ok := t.(ticket.TicketVanadiumTicket) 101 if !ok { 102 return fmt.Errorf("Not a VanadiumTicket: %#v", t) 103 } 104 105 var blessings security.Blessings 106 if err := base64urlVomDecode(vanadiumTicket.Value.Blessing, &blessings); err != nil { 107 return err 108 } 109 110 vlog.Info(blessings) 111 112 if err := principal.BlessingStore().SetDefault(blessings); err != nil { 113 return err 114 } 115 if _, err := principal.BlessingStore().Set(blessings, "..."); err != nil { 116 return err 117 } 118 if err := security.AddToRoots(principal, blessings); err != nil { 119 return fmt.Errorf("failed to add blessings to recognized roots: %v", err) 120 } 121 122 fmt.Printf("Public key: %s\n", principal.PublicKey()) 123 fmt.Println("---------------- BlessingStore ----------------") 124 fmt.Print(principal.BlessingStore().DebugString()) 125 fmt.Println("---------------- BlessingRoots ----------------") 126 fmt.Print(principal.Roots().DebugString()) 127 128 return nil 129 } 130 131 func bless(ctx *context.T, p security.Principal, name string) (security.Blessings, error) { 132 caveat, err := security.NewExpiryCaveat(time.Now().Add(durationFlag)) 133 if err != nil { 134 ctx.Errorf("Couldn't create caveat") 135 return security.Blessings{}, err 136 } 137 rp := v23.GetPrincipal(ctx) 138 rblessing, _ := rp.BlessingStore().Default() 139 return rp.Bless(p.PublicKey(), rblessing, name, caveat) 140 } 141 142 func base64urlVomDecode(s string, i interface{}) error { 143 b, err := base64.URLEncoding.DecodeString(s) 144 if err != nil { 145 return err 146 } 147 dec := vom.NewDecoder(bytes.NewBuffer(b)) 148 return dec.Decode(i) 149 } 150 151 func main() { 152 cmdline.HideGlobalFlagsExcept() 153 cmdline.Main(newCmdRoot()) 154 }