github.com/sl1pm4t/consul@v1.4.5-0.20190325224627-74c31c540f9c/command/acl/token/update/token_update.go (about) 1 package tokenupdate 2 3 import ( 4 "flag" 5 "fmt" 6 7 "github.com/hashicorp/consul/api" 8 "github.com/hashicorp/consul/command/acl" 9 "github.com/hashicorp/consul/command/flags" 10 "github.com/mitchellh/cli" 11 ) 12 13 func New(ui cli.Ui) *cmd { 14 c := &cmd{UI: ui} 15 c.init() 16 return c 17 } 18 19 type cmd struct { 20 UI cli.Ui 21 flags *flag.FlagSet 22 http *flags.HTTPFlags 23 help string 24 25 tokenID string 26 policyIDs []string 27 policyNames []string 28 description string 29 mergePolicies bool 30 showMeta bool 31 upgradeLegacy bool 32 } 33 34 func (c *cmd) init() { 35 c.flags = flag.NewFlagSet("", flag.ContinueOnError) 36 c.flags.BoolVar(&c.showMeta, "meta", false, "Indicates that token metadata such "+ 37 "as the content hash and raft indices should be shown for each entry") 38 c.flags.BoolVar(&c.mergePolicies, "merge-policies", false, "Merge the new policies "+ 39 "with the existing policies") 40 c.flags.StringVar(&c.tokenID, "id", "", "The Accessor ID of the token to read. "+ 41 "It may be specified as a unique ID prefix but will error if the prefix "+ 42 "matches multiple token Accessor IDs") 43 c.flags.StringVar(&c.description, "description", "", "A description of the token") 44 c.flags.Var((*flags.AppendSliceValue)(&c.policyIDs), "policy-id", "ID of a "+ 45 "policy to use for this token. May be specified multiple times") 46 c.flags.Var((*flags.AppendSliceValue)(&c.policyNames), "policy-name", "Name of a "+ 47 "policy to use for this token. May be specified multiple times") 48 c.flags.BoolVar(&c.upgradeLegacy, "upgrade-legacy", false, "Add new polices "+ 49 "to a legacy token replacing all existing rules. This will cause the legacy "+ 50 "token to behave exactly like a new token but keep the same Secret.\n"+ 51 "WARNING: you must ensure that the new policy or policies specified grant "+ 52 "equivalent or appropriate access for the existing clients using this token.") 53 54 c.http = &flags.HTTPFlags{} 55 flags.Merge(c.flags, c.http.ClientFlags()) 56 flags.Merge(c.flags, c.http.ServerFlags()) 57 c.help = flags.Usage(help, c.flags) 58 } 59 60 func (c *cmd) Run(args []string) int { 61 if err := c.flags.Parse(args); err != nil { 62 return 1 63 } 64 65 if c.tokenID == "" { 66 c.UI.Error(fmt.Sprintf("Cannot update a token without specifying the -id parameter")) 67 return 1 68 } 69 70 client, err := c.http.APIClient() 71 if err != nil { 72 c.UI.Error(fmt.Sprintf("Error connecting to Consul agent: %s", err)) 73 return 1 74 } 75 76 tokenID, err := acl.GetTokenIDFromPartial(client, c.tokenID) 77 if err != nil { 78 c.UI.Error(fmt.Sprintf("Error determining token ID: %v", err)) 79 return 1 80 } 81 82 token, _, err := client.ACL().TokenRead(tokenID, nil) 83 if err != nil { 84 c.UI.Error(fmt.Sprintf("Error when retrieving current token: %v", err)) 85 return 1 86 } 87 88 if c.upgradeLegacy { 89 if token.Rules == "" { 90 // This is just for convenience it should actually be harmless to allow it 91 // to go through anyway. 92 c.UI.Error(fmt.Sprintf("Can't use -upgrade-legacy on a non-legacy token")) 93 return 1 94 } 95 // Reset the rules to nothing forcing this to be updated as a non-legacy 96 // token but with same secret. 97 token.Rules = "" 98 } 99 100 if c.description != "" { 101 // Only update description if the user specified a new one. This does make 102 // it impossible to completely clear descriptions from CLI but that seems 103 // better than silently deleting descriptions when using command without 104 // manually giving the new description. If it's a real issue we can always 105 // add another explicit `-remove-description` flag but it feels like an edge 106 // case that's not going to be critical to anyone. 107 token.Description = c.description 108 } 109 110 if c.mergePolicies { 111 for _, policyName := range c.policyNames { 112 found := false 113 for _, link := range token.Policies { 114 if link.Name == policyName { 115 found = true 116 break 117 } 118 } 119 120 if !found { 121 // We could resolve names to IDs here but there isn't any reason why its would be better 122 // than allowing the agent to do it. 123 token.Policies = append(token.Policies, &api.ACLTokenPolicyLink{Name: policyName}) 124 } 125 } 126 127 for _, policyID := range c.policyIDs { 128 policyID, err := acl.GetPolicyIDFromPartial(client, policyID) 129 if err != nil { 130 c.UI.Error(fmt.Sprintf("Error resolving policy ID %s: %v", policyID, err)) 131 return 1 132 } 133 found := false 134 135 for _, link := range token.Policies { 136 if link.ID == policyID { 137 found = true 138 break 139 } 140 } 141 142 if !found { 143 token.Policies = append(token.Policies, &api.ACLTokenPolicyLink{ID: policyID}) 144 } 145 } 146 } else { 147 token.Policies = nil 148 149 for _, policyName := range c.policyNames { 150 // We could resolve names to IDs here but there isn't any reason why its would be better 151 // than allowing the agent to do it. 152 token.Policies = append(token.Policies, &api.ACLTokenPolicyLink{Name: policyName}) 153 } 154 155 for _, policyID := range c.policyIDs { 156 policyID, err := acl.GetPolicyIDFromPartial(client, policyID) 157 if err != nil { 158 c.UI.Error(fmt.Sprintf("Error resolving policy ID %s: %v", policyID, err)) 159 return 1 160 } 161 token.Policies = append(token.Policies, &api.ACLTokenPolicyLink{ID: policyID}) 162 } 163 } 164 165 token, _, err = client.ACL().TokenUpdate(token, nil) 166 if err != nil { 167 c.UI.Error(fmt.Sprintf("Failed to update token %s: %v", tokenID, err)) 168 return 1 169 } 170 171 c.UI.Info("Token updated successfully.") 172 acl.PrintToken(token, c.UI, c.showMeta) 173 return 0 174 } 175 176 func (c *cmd) Synopsis() string { 177 return synopsis 178 } 179 180 func (c *cmd) Help() string { 181 return flags.Usage(c.help, nil) 182 } 183 184 const synopsis = "Update an ACL Token" 185 const help = ` 186 Usage: consul acl token update [options] 187 188 This command will update a token. Some parts such as marking the token local 189 cannot be changed. 190 191 Update a token description and take the policies from the existing token: 192 193 $ consul acl token update -id abcd -description "replication" -merge-policies 194 195 Update all editable fields of the token: 196 197 $ consul acl token update -id abcd -description "replication" -policy-name "token-replication" 198 `