github.com/outbrain/consul@v1.4.5/website/source/docs/guides/acl-migrate-tokens.html.md (about) 1 --- 2 layout: "docs" 3 page_title: "ACL Token Migration" 4 sidebar_current: "docs-guides-acl-migrate-tokens" 5 description: |- 6 Consul 1.4.0 introduces a new ACL system with improvements for the security and 7 management of ACL tokens and policies. This guide documents how to upgrade 8 existing (now called "legacy") tokens after upgrading to 1.4.0. 9 --- 10 11 # ACL Token Migration 12 13 Consul 1.4.0 introduces a new ACL system with improvements for the security and 14 management of ACL tokens and policies. This guide documents how to upgrade 15 existing (now called "legacy") tokens after upgrading to 1.4.0. 16 17 Since the policy syntax changed to be more precise and flexible to manage, it's 18 necessary to manually translate old tokens into new ones to take advantage of 19 the new ACL system features. Tooling is provided to help automate this and this 20 guide describes the overall process. 21 22 ~> **Note:** **1.4.0 retains full support for "legacy" ACL tokens** so upgrades 23 from Consul 1.3.0 are safe. Existing tokens will continue to work in the same 24 way for at least two "major" releases (1.5.x, 1.6.x, etc; note HashiCorp does 25 not use SemVer for our products). 26 27 This document will briefly describe [what changed](#what-changed), and then walk 28 through the [high-level migration process options](#migration-process), finally 29 giving some [specific examples](#migration-examples) of migration strategies. 30 31 ## New ACL System Differences 32 33 The [ACL guide](/docs/guides/acl.html) and [legacy ACL 34 guide](/docs/guides/acl-legacy.html) describes the new and old systems in 35 detail. Below is a summary of the changes that need to be considered when 36 migrating legacy tokens to the new system. 37 38 ### Token and Policy Separation 39 40 You can use a single policy in the new system for all tokens that share access 41 rules. For example, all tokens created using the clone endpoint in the legacy 42 system can be represented with a single policy and a set of tokens that map to 43 that policy. 44 45 ### Rule Syntax Changes 46 47 The most significant change is that rules with selectors _no longer prefix match 48 by default_. In the legacy system the following rules would grant access to 49 nodes, services and keys _prefixed_ with foo. 50 51 ``` 52 node "foo" { policy = "write" } 53 service "foo" { policy = "write" } 54 key "foo" { policy = "write" } 55 ``` 56 57 In the new system the same syntax will only perform _exact_ match on the whole 58 node name, service name or key. 59 60 In general, exact match is what most operators intended most of the time so the 61 same policy can be kept, however if you rely on prefix match behavior then using 62 the same syntax will break behavior. 63 64 Prefix matching can be expressed in the new ACL system explicitly, making the 65 following rules in the new system exactly the same as the rules above in the 66 old. 67 68 ``` 69 node_prefix "foo" { policy = "write" } 70 service_prefix "foo" { policy = "write" } 71 key_prefix "foo" { policy = "write" } 72 ``` 73 74 ### API Separation 75 76 The "old" API endpoints below continue to work for backwards compatibility but 77 will continue to create or show only "legacy" tokens that can't take full 78 advantage of the new ACL system improvements. They are documented fully under 79 [Legacy Tokens](/api/acl/legacy.html). 80 81 - [`PUT /acl/create` - Create Legacy Token](/api/acl/legacy.html#create-acl-token) 82 - [`PUT /acl/update` - Update Legacy Token](/api/acl/legacy.html#update-acl-token) 83 - [`PUT /acl/destroy/:uuid` - Delete Legacy Token](/api/acl/legacy.html#delete-acl-token) 84 - [`GET /acl/info/:uuid` - Read Legacy Token](/api/acl/legacy.html#read-acl-token) 85 - [`PUT /acl/clone/:uuid` - Clone Legacy Token](/api/acl/legacy.html#clone-acl-token) 86 - [`GET /acl/list` - List Legacy Tokens](/api/acl/legacy.html#list-acls) 87 88 The new ACL system includes new API endpoints to manage 89 the [ACL System](/api/acl/acl.html), [Tokens](/api/acl/tokens.html) 90 and [Policies](/api/acl/policies.html). 91 92 ## Migration Process 93 94 While "legacy" tokens will continue to work for several major releases, it's 95 advisable to plan on migrating existing tokens as soon as is convenient. 96 Migrating also enables using the new policy management improvements, stricter 97 policy syntax rules and other features of the new system without 98 re-issuing all the secrets in use. 99 100 The high-level process for migrating a legacy token is as follows: 101 102 1. Create a new policy or policies that grant the required access 103 2. Update the existing token to use those policies 104 105 ### Prerequisites 106 107 This process assumes that the 1.4.0 upgrade is complete including all legacy 108 ACLs having their accessor IDs populated. This might take up to several minutes 109 after the servers upgrade in the primary datacenter. You can tell if this is the 110 case by using `consul acl token list` and checking that no tokens exist with a 111 blank `AccessorID`. 112 113 In addition, it is assumed that all clients that might _create_ ACL tokens (e.g. 114 Vault's Consul secrets engine) have been updated to use the [new ACL 115 APIs](/docs/guides/acl-migrate-tokens.html#api-separation). 116 117 Specifically if you are using Vault's Consul secrets engine you need to be 118 running Vault 1.0.0 or higher, _and_ you must update all roles defined in Vault 119 to specify a list of policy names rather than an inline policy (which causes 120 Vault to use the legacy API). 121 122 ~> **Note:** if you have systems still creating "legacy" tokens with the old 123 APIs, the migration steps below will still work, however you'll have to keep 124 re-running them until nothing is creating legacy tokens to ensure all tokens are 125 migrated. 126 127 ### Creating Policies 128 129 There are a range of different strategies for creating new policies from existing 130 tokens. Two high-level strategies are described here although others or a 131 mixture of these may be most appropriate depending on the ACL tokens you already 132 have. 133 134 #### Strategy 1: Simple Policy Mapping 135 136 The simplest and most automatic strategy is to create one new policy for every 137 existing token. This is easy to automate, but may result in a lot of policies 138 with exactly the same rules and with non-human-readable names which will make 139 managing policies harder. This approach can be accomplished using the [`consul 140 acl policy create`](/docs/commands/acl/acl-policy.html#create) command with 141 `-from-token` option. 142 143 | Pros | Cons | 144 | ---- | ---- | 145 | ✅ Simple | ❌ May leave many duplicated policies | 146 | ✅ Easy to automate | ❌ Policy names not human-readable | 147 148 A detailed example of using this approach is [given 149 below](#simple-policy-mapping). 150 151 #### Strategy 2: Combining Policies 152 153 This strategy takes a more manual approach to create a more manageable set of 154 policies. There are a spectrum of options for how to do this which tradeoff 155 increasing human involvement for increasing clarity and re-usability of the 156 resulting policies. 157 158 For example you could use hashes of the policy rules to de-duplicate identical 159 token policies automatically, however naming them something meaningful for 160 humans would likely still need manual intervention. 161 162 Toward the other end of the spectrum it might be beneficial for security to 163 translate prefix matches into exact matches. This however requires the operator 164 knowing that clients using the token really doesn't rely on the prefix matching 165 semantics of the old ACL system. 166 167 To assist with this approach, there is a CLI tool and corresponding API that can 168 translate a legacy ACL token's rules into a new ACL policy that is exactly 169 equivalent. See [`consul acl 170 translate-rules`](/docs/commands/acl/acl-translate-rules.html). 171 172 | Pros | Cons | 173 | ---- | ---- | 174 | ✅ Clearer, more manageable policies | ❌ Requires more manual effort | 175 | ✅ Policies can be re-used by new ACL tokens | ❌ May take longer for large or complex existing policy sets | 176 177 A detailed example of using this approach is [given below](#combining-policies). 178 179 ### Updating Existing Tokens 180 181 Once you have created one or more policies that adequately express the rules 182 needed for a legacy token, you can update the token via the CLI or API to use 183 those policies. 184 185 After updating, the token is no longer considered "legacy" and will have all the 186 properties of a new token, however it keeps it's `SecretID` (the secret part of 187 the token used in API calls) so clients already using that token will continue 188 to work. It is assumed that the policies you attach continue to grant the 189 necessary access for existing clients; this is up to the operator to ensure. 190 191 #### Update via API 192 193 Use the [`PUT /v1/acl/token/:AccessorID`](/api/acl/tokens.html#update-a-token) 194 endpoint. Specifically, ensure that the `Rules` field is omitted or empty. Empty 195 `Rules` indicates that this is now treated as a new token. 196 197 #### Update via CLI 198 199 Use the [`consul acl token update`](/docs/commands/acl/acl-token.html#update) 200 command to update the token. Specifically you need to use `-upgrade-legacy` 201 which will ensure that legacy rules are removed as well as the new policies 202 added. 203 204 ## Migration Examples 205 206 Below are two detailed examples of the two high-level strategies for creating 207 polices discussed above. It should be noted these are intended to clarify the 208 concrete steps you might take. **We don't recommend you perform production 209 migrations with ad-hoc terminal commands**. Combining these or something similar 210 into a script might be appropriate. 211 212 ### Simple Policy Mapping 213 214 This strategy uses the CLI to create a new policy for every existing legacy 215 token with exactly equivalent rules. It's easy to automate and clients will see 216 no change in behavior for their tokens, but it does leave you with a lot of 217 potentially identical policies to manage or clean up later. 218 219 #### Create Policies 220 221 You can get the AccessorID of every legacy token from the API. For example, 222 using `curl` and `jq` in bash: 223 224 ```sh 225 $ LEGACY_IDS=$(curl -sH "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ 226 'localhost:8500/v1/acl/tokens' | jq -r '.[] | select (.Legacy) | .AccessorID') 227 $ echo "$LEGACY_IDS" 228 621cbd12-dde7-de06-9be0-e28d067b5b7f 229 65cecc86-eb5b-ced5-92dc-f861cf7636fe 230 ba464aa8-d857-3d26-472c-4d49c3bdae72 231 ``` 232 233 To create a policy for each one we can use something like: 234 235 ```sh 236 for id in $LEGACY_IDS; do \ 237 consul acl policy create -name "migrated-$id" -from-token $id \ 238 -description "Migrated from legacy ACL token"; \ 239 done 240 ``` 241 242 Each policy now has an identical set of rules to the original token. You can 243 inspect these: 244 245 ```sh 246 $ consul acl policy read -name migrated-621cbd12-dde7-de06-9be0-e28d067b5b7f 247 ID: 573d84bd-8b08-3061-e391-d2602e1b4947 248 Name: migrated-621cbd12-dde7-de06-9be0-e28d067b5b7f 249 Description: Migrated from legacy ACL token 250 Datacenters: 251 Rules: 252 service_prefix "" { 253 policy = "write" 254 } 255 ``` 256 257 Notice how the policy here is `service_prefix` and not `service` since the old 258 ACL syntax was an implicit prefix match. This ensures any clients relying on 259 prefix matching behavior will still work. 260 261 #### Update Tokens 262 263 With the policies created as above, we can automatically upgrade all legacy 264 tokens. 265 266 ```sh 267 for id in $LEGACY_IDS; do \ 268 consul acl token update -id $id -policy-name "migrated-$id" -upgrade-legacy; \ 269 done 270 ``` 271 272 The update is now complete, all legacy tokens are now new tokens with identical 273 secrets and enforcement rules. 274 275 ### Combining Policies 276 277 This strategy has more manual elements but results in a cleaner and more 278 manageable set of policies than the fully automatic solutions. Note that this is 279 **just an example** to illustrate a few ways you may choose to merge or 280 manipulate policies. 281 282 #### Find All Unique Policies 283 284 You can get the AccessorID of every legacy token from the API. For example, 285 using `curl` and `jq` in bash: 286 287 ```sh 288 $ LEGACY_IDS=$(curl -sH "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ 289 'localhost:8500/v1/acl/tokens' | jq -r '.[] | select (.Legacy) | .AccessorID') 290 $ echo "$LEGACY_IDS" 291 8b65fdf9-303e-0894-9f87-e71b3273600c 292 d9deb39b-1b30-e100-b9c5-04aba3f593a1 293 f2bce42e-cdcc-848d-28ca-cfd0556a22e3 294 ``` 295 296 Now we want to read the actual policy for each legacy token and de-duplicate 297 them. We can use the `translate-rules` helper sub-command which will read the 298 token's policy and return a new ACL policy that is exactly equivalent. 299 300 ```sh 301 $ for id in $LEGACY_IDS; do \ 302 echo "Policy for $id:" 303 consul acl translate-rules -token-accessor "$id"; \ 304 done 305 Policy for 8b65fdf9-303e-0894-9f87-e71b3273600c: 306 service_prefix "bar" { 307 policy = "write" 308 } 309 Policy for d9deb39b-1b30-e100-b9c5-04aba3f593a1: 310 service_prefix "foo" { 311 policy = "write" 312 } 313 Policy for f2bce42e-cdcc-848d-28ca-cfd0556a22e3: 314 service_prefix "bar" { 315 policy = "write" 316 } 317 ``` 318 319 Notice that two policies are the same and one different. 320 321 We can change the loop above to take a hash of this policy definition to 322 de-duplicate the policies into a set of files locally. This example uses command 323 available on macOS but equivalents for other platforms should be easy to find. 324 325 ```sh 326 $ mkdir policies 327 $ for id in $LEGACY_IDS; do \ 328 # Fetch the equivalent new policy rules based on the legacy token rules 329 NEW_POLICY=$(consul acl translate-rules -token-accessor "$id"); \ 330 # Sha1 hash the rules 331 HASH=$(echo -n "$NEW_POLICY" | shasum | awk '{ print $1 }'); \ 332 # Write rules to a policy file named with the hash to de-duplicated 333 echo "$NEW_POLICY" > policies/$HASH.hcl; \ 334 done 335 $ tree policies 336 policies 337 ├── 024ce11f26f59436c518fb31f0999d1400485c17.hcl 338 └── 501b787c9444fbd62f346ab257eeb27197be2444.hcl 339 ``` 340 341 #### Cleaning Up Policies 342 343 You can now manually inspect and potentially edit these policies. For example we 344 could rename them according to their intended use. In this case we maintain the 345 hash as it will allow us to match tokens to policies later. 346 347 ```sh 348 $ cat policies/024ce11f26f59436c518fb31f0999d1400485c17.hcl 349 service_prefix "bar" { 350 policy = "write" 351 } 352 $ # Add human-readable suffix to the file name so policies end up clearly named 353 $ mv policies/024ce11f26f59436c518fb31f0999d1400485c17.hcl \ 354 policies/024ce11f26f59436c518fb31f0999d1400485c17-bar-service.hcl 355 ``` 356 357 You might also choose to tighten up the rules, for example if you know you never 358 rely on prefix-matching the service name `foo` you might choose to modify the 359 policy to use exact match. 360 361 ```sh 362 $ cat policies/501b787c9444fbd62f346ab257eeb27197be2444.hcl 363 service_prefix "foo" { 364 policy = "write" 365 } 366 $ echo 'service "foo" { policy = "write" }' > policies/501b787c9444fbd62f346ab257eeb27197be2444.hcl 367 $ # Add human-readable suffix to the file name so policies end up clearly named 368 $ mv policies/501b787c9444fbd62f346ab257eeb27197be2444.hcl \ 369 policies/501b787c9444fbd62f346ab257eeb27197be2444-foo-service.hcl 370 ``` 371 372 #### Creating Policies 373 374 We now have a minimal set of policies to create, with human-readable names. We 375 can create each one with something like the following. 376 377 ```sh 378 $ for p in $(ls policies | grep ".hcl"); do \ 379 # Extract the hash part of the file name 380 HASH=$(echo "$p" | cut -d - -f 1); \ 381 # Extract the name suffix without .hcl 382 NAME=$(echo "$p" | cut -d - -f 2- | cut -d . -f 1); \ 383 # Create new policy based on the rules in the file and the name we gave 384 consul acl policy create -name $NAME \ 385 -rules "@policies/$p" \ 386 -description "Migrated from legacy token"; \ 387 done 388 ID: da2a9f9b-4e44-13f8-e308-76ce7a8dcb21 389 Name: bar-service 390 Description: Migrated from legacy token 391 Datacenters: 392 Rules: 393 service_prefix "bar" { 394 policy = "write" 395 } 396 397 ID: 9fbded86-9140-efe4-b661-c8bd07b6c584 398 Name: foo-service 399 Description: Migrated from legacy token 400 Datacenters: 401 Rules: 402 service "foo" { policy = "write" } 403 404 ``` 405 406 #### Upgrading Tokens 407 408 Finally we can map our existing tokens to those policies using the hash in the 409 policy file names. The `-upgrade-legacy` flag removes the token's legacy 410 embedded rules at the same time as associating them with the new policies 411 created from those rules. 412 413 ```sh 414 $ for id in $LEGACY_IDS; do \ 415 NEW_POLICY=$(consul acl translate-rules -token-accessor "$id"); \ 416 HASH=$(echo -n "$NEW_POLICY" | shasum | awk '{ print $1 }'); \ 417 # Lookup the hash->new policy mapping from the policy file names 418 POLICY_FILE=$(ls policies | grep "^$HASH"); \ 419 POLICY_NAME=$(echo "$POLICY_FILE" | cut -d - -f 2- | cut -d . -f 1); \ 420 echo "==> Mapping token $id to policy $POLICY_NAME"; \ 421 consul acl token update -id $id -policy-name $POLICY_NAME -upgrade-legacy; \ 422 done 423 ==> Mapping token 8b65fdf9-303e-0894-9f87-e71b3273600c to policy bar-service 424 Token updated successfully. 425 AccessorID: 8b65fdf9-303e-0894-9f87-e71b3273600c 426 SecretID: 3dbb3981-7654-733a-3475-5ce20fc5a7b9 427 Description: 428 Local: false 429 Create Time: 0001-01-01 00:00:00 +0000 UTC 430 Policies: 431 da2a9f9b-4e44-13f8-e308-76ce7a8dcb21 - bar-service 432 ==> Mapping token d9deb39b-1b30-e100-b9c5-04aba3f593a1 to policy foo-service 433 Token updated successfully. 434 AccessorID: d9deb39b-1b30-e100-b9c5-04aba3f593a1 435 SecretID: 5f54733b-4c76-eb74-8781-3550c20f4969 436 Description: 437 Local: false 438 Create Time: 0001-01-01 00:00:00 +0000 UTC 439 Policies: 440 9fbded86-9140-efe4-b661-c8bd07b6c584 - foo-service 441 ==> Mapping token f2bce42e-cdcc-848d-28ca-cfd0556a22e3 to policy bar-service 442 Token updated successfully. 443 AccessorID: f2bce42e-cdcc-848d-28ca-cfd0556a22e3 444 SecretID: f3aaa3e2-2c6f-cf3c-1e86-454de728e8ab 445 Description: 446 Local: false 447 Create Time: 0001-01-01 00:00:00 +0000 UTC 448 Policies: 449 da2a9f9b-4e44-13f8-e308-76ce7a8dcb21 - bar-service 450 ``` 451 452 At this point all tokens are upgraded and can use new ACL features while 453 retaining the same secret clients are already using.