Robert Kroeger | 9010452 | 2014-11-11 15:29:17 -0800 | [diff] [blame] | 1 | package main |
| 2 | |
| 3 | // Commands to get/set ACLs. |
| 4 | |
| 5 | import ( |
| 6 | "fmt" |
Robert Kroeger | 9010452 | 2014-11-11 15:29:17 -0800 | [diff] [blame] | 7 | |
Jiri Simsa | bc26d69 | 2014-11-19 18:30:55 -0800 | [diff] [blame] | 8 | "veyron.io/lib/cmdline" |
Robert Kroeger | 1e4721a | 2014-11-12 17:59:46 -0800 | [diff] [blame] | 9 | "veyron.io/veyron/veyron2/security" |
Robert Kroeger | 9010452 | 2014-11-11 15:29:17 -0800 | [diff] [blame] | 10 | "veyron.io/veyron/veyron2/services/mgmt/node" |
Robert Kroeger | 1e4721a | 2014-11-12 17:59:46 -0800 | [diff] [blame] | 11 | "veyron.io/veyron/veyron2/services/security/access" |
| 12 | "veyron.io/veyron/veyron2/verror" |
Robert Kroeger | 9010452 | 2014-11-11 15:29:17 -0800 | [diff] [blame] | 13 | ) |
| 14 | |
| 15 | var cmdGet = &cmdline.Command{ |
| 16 | Run: runGet, |
| 17 | Name: "get", |
| 18 | Short: "Get ACLs for the given target.", |
Robert Kroeger | 2c25fcf | 2014-11-17 09:44:59 -0800 | [diff] [blame] | 19 | Long: "Get ACLs for the given target.", |
Robert Kroeger | 9010452 | 2014-11-11 15:29:17 -0800 | [diff] [blame] | 20 | ArgsName: "<node manager name>", |
| 21 | ArgsLong: ` |
| 22 | <node manager name> can be a Vanadium name for a node manager, |
| 23 | application installation or instance.`, |
| 24 | } |
| 25 | |
Robert Kroeger | 9010452 | 2014-11-11 15:29:17 -0800 | [diff] [blame] | 26 | func runGet(cmd *cmdline.Command, args []string) error { |
Robert Kroeger | 9010452 | 2014-11-11 15:29:17 -0800 | [diff] [blame] | 27 | if expected, got := 1, len(args); expected != got { |
Robert Kroeger | 2c25fcf | 2014-11-17 09:44:59 -0800 | [diff] [blame] | 28 | return cmd.UsageErrorf("get: incorrect number of arguments, expected %d, got %d", expected, got) |
Robert Kroeger | 9010452 | 2014-11-11 15:29:17 -0800 | [diff] [blame] | 29 | } |
| 30 | |
| 31 | vanaName := args[0] |
Matt Rosencrantz | 5180d16 | 2014-12-03 13:48:40 -0800 | [diff] [blame] | 32 | objACL, _, err := node.ApplicationClient(vanaName).GetACL(runtime.NewContext()) |
Robert Kroeger | 9010452 | 2014-11-11 15:29:17 -0800 | [diff] [blame] | 33 | if err != nil { |
| 34 | return fmt.Errorf("GetACL on %s failed: %v", vanaName, err) |
| 35 | } |
Asim Shankar | 6888519 | 2014-11-26 12:48:35 -0800 | [diff] [blame] | 36 | // Convert objACL (TaggedACLMap) into aclEntries for pretty printing. |
| 37 | entries := make(aclEntries) |
| 38 | for tag, acl := range objACL { |
| 39 | for _, p := range acl.In { |
| 40 | entries.Tags(string(p))[tag] = false |
| 41 | } |
| 42 | for _, b := range acl.NotIn { |
| 43 | entries.Tags(b)[tag] = true |
| 44 | } |
Robert Kroeger | 9010452 | 2014-11-11 15:29:17 -0800 | [diff] [blame] | 45 | } |
Asim Shankar | 6888519 | 2014-11-26 12:48:35 -0800 | [diff] [blame] | 46 | fmt.Fprintf(cmd.Stdout(), "%v", entries) |
Robert Kroeger | 9010452 | 2014-11-11 15:29:17 -0800 | [diff] [blame] | 47 | return nil |
| 48 | } |
| 49 | |
Robert Kroeger | 1e4721a | 2014-11-12 17:59:46 -0800 | [diff] [blame] | 50 | var cmdSet = &cmdline.Command{ |
| 51 | Run: runSet, |
| 52 | Name: "set", |
| 53 | Short: "Set ACLs for the given target.", |
| 54 | Long: "Set ACLs for the given target", |
Asim Shankar | 6888519 | 2014-11-26 12:48:35 -0800 | [diff] [blame] | 55 | ArgsName: "<node manager name> (<blessing> [!]<tag>(,[!]<tag>)*", |
Robert Kroeger | 1e4721a | 2014-11-12 17:59:46 -0800 | [diff] [blame] | 56 | ArgsLong: ` |
| 57 | <node manager name> can be a Vanadium name for a node manager, |
| 58 | application installation or instance. |
| 59 | |
| 60 | <blessing> is a blessing pattern. |
Asim Shankar | 6888519 | 2014-11-26 12:48:35 -0800 | [diff] [blame] | 61 | If the same pattern is repeated multiple times in the command, then |
| 62 | the only the last occurrence will be honored. |
Robert Kroeger | 1e4721a | 2014-11-12 17:59:46 -0800 | [diff] [blame] | 63 | |
Asim Shankar | 6888519 | 2014-11-26 12:48:35 -0800 | [diff] [blame] | 64 | <tag> is a subset of defined access types ("Admin", "Read", "Write" etc.). |
| 65 | If the access right is prefixed with a '!' then <blessing> is added to the |
| 66 | NotIn list for that right. Using "^" as a "tag" causes all occurrences of |
| 67 | <blessing> in the current ACL to be cleared. |
Robert Kroeger | 1e4721a | 2014-11-12 17:59:46 -0800 | [diff] [blame] | 68 | |
Asim Shankar | 6888519 | 2014-11-26 12:48:35 -0800 | [diff] [blame] | 69 | Examples: |
| 70 | set root/self ^ |
| 71 | will remove "root/self" from the In and NotIn lists for all access rights. |
Robert Kroeger | 1e4721a | 2014-11-12 17:59:46 -0800 | [diff] [blame] | 72 | |
Asim Shankar | 6888519 | 2014-11-26 12:48:35 -0800 | [diff] [blame] | 73 | set root/self Read,!Write |
| 74 | will add "root/self" to the In list for Read access and the NotIn list |
| 75 | for Write access (and remove "root/self" from both the In and NotIn |
| 76 | lists of all other access rights)`, |
Robert Kroeger | 1e4721a | 2014-11-12 17:59:46 -0800 | [diff] [blame] | 77 | } |
| 78 | |
| 79 | func runSet(cmd *cmdline.Command, args []string) error { |
| 80 | if got := len(args); !((got%2) == 1 && got >= 3) { |
| 81 | return cmd.UsageErrorf("set: incorrect number of arguments %d, must be 1 + 2n", got) |
| 82 | } |
| 83 | |
| 84 | vanaName := args[0] |
| 85 | pairs := args[1:] |
| 86 | |
Asim Shankar | 6888519 | 2014-11-26 12:48:35 -0800 | [diff] [blame] | 87 | entries := make(aclEntries) |
Robert Kroeger | 1e4721a | 2014-11-12 17:59:46 -0800 | [diff] [blame] | 88 | for i := 0; i < len(pairs); i += 2 { |
Asim Shankar | 6888519 | 2014-11-26 12:48:35 -0800 | [diff] [blame] | 89 | blessing := pairs[i] |
| 90 | tags, err := parseAccessTags(pairs[i+1]) |
| 91 | if err != nil { |
| 92 | return cmd.UsageErrorf("failed to parse access tags for %q: %v", blessing, err) |
Robert Kroeger | 1e4721a | 2014-11-12 17:59:46 -0800 | [diff] [blame] | 93 | } |
Asim Shankar | 6888519 | 2014-11-26 12:48:35 -0800 | [diff] [blame] | 94 | entries[blessing] = tags |
Robert Kroeger | 1e4721a | 2014-11-12 17:59:46 -0800 | [diff] [blame] | 95 | } |
| 96 | |
Asim Shankar | 6888519 | 2014-11-26 12:48:35 -0800 | [diff] [blame] | 97 | // Set the ACLs on the specified names. |
Matt Rosencrantz | 5180d16 | 2014-12-03 13:48:40 -0800 | [diff] [blame] | 98 | ctx := runtime.NewContext() |
Robert Kroeger | 1e4721a | 2014-11-12 17:59:46 -0800 | [diff] [blame] | 99 | for { |
Matt Rosencrantz | 5180d16 | 2014-12-03 13:48:40 -0800 | [diff] [blame] | 100 | objACL, etag, err := node.ApplicationClient(vanaName).GetACL(ctx) |
Robert Kroeger | 1e4721a | 2014-11-12 17:59:46 -0800 | [diff] [blame] | 101 | if err != nil { |
| 102 | return cmd.UsageErrorf("GetACL(%s) failed: %v", vanaName, err) |
| 103 | } |
Asim Shankar | 6888519 | 2014-11-26 12:48:35 -0800 | [diff] [blame] | 104 | for blessingOrPattern, tags := range entries { |
| 105 | objACL.Clear(blessingOrPattern) // Clear out any existing references |
| 106 | for tag, blacklist := range tags { |
| 107 | if blacklist { |
| 108 | objACL.Blacklist(blessingOrPattern, tag) |
| 109 | } else { |
| 110 | objACL.Add(security.BlessingPattern(blessingOrPattern), tag) |
| 111 | } |
Robert Kroeger | 1e4721a | 2014-11-12 17:59:46 -0800 | [diff] [blame] | 112 | } |
Robert Kroeger | 1e4721a | 2014-11-12 17:59:46 -0800 | [diff] [blame] | 113 | } |
Matt Rosencrantz | 5180d16 | 2014-12-03 13:48:40 -0800 | [diff] [blame] | 114 | switch err := node.ApplicationClient(vanaName).SetACL(ctx, objACL, etag); { |
Robert Kroeger | 1e4721a | 2014-11-12 17:59:46 -0800 | [diff] [blame] | 115 | case err != nil && !verror.Is(err, access.ErrBadEtag): |
| 116 | return cmd.UsageErrorf("SetACL(%s) failed: %v", vanaName, err) |
| 117 | case err == nil: |
| 118 | return nil |
| 119 | } |
| 120 | fmt.Fprintf(cmd.Stderr(), "WARNING: trying again because of asynchronous change\n") |
| 121 | } |
| 122 | return nil |
| 123 | } |
Robert Kroeger | 9010452 | 2014-11-11 15:29:17 -0800 | [diff] [blame] | 124 | |
| 125 | func aclRoot() *cmdline.Command { |
| 126 | return &cmdline.Command{ |
| 127 | Name: "acl", |
Robert Kroeger | 1e4721a | 2014-11-12 17:59:46 -0800 | [diff] [blame] | 128 | Short: "Tool for setting node manager ACLs", |
Robert Kroeger | 9010452 | 2014-11-11 15:29:17 -0800 | [diff] [blame] | 129 | Long: ` |
Robert Kroeger | 2c25fcf | 2014-11-17 09:44:59 -0800 | [diff] [blame] | 130 | The acl tool manages ACLs on the node manger, installations and instances. |
Robert Kroeger | 9010452 | 2014-11-11 15:29:17 -0800 | [diff] [blame] | 131 | `, |
Robert Kroeger | 1e4721a | 2014-11-12 17:59:46 -0800 | [diff] [blame] | 132 | Children: []*cmdline.Command{cmdGet, cmdSet}, |
Robert Kroeger | 9010452 | 2014-11-11 15:29:17 -0800 | [diff] [blame] | 133 | } |
| 134 | } |