Implement CLI token cloning & special ID handling (#4827)

* Implement CLI token cloning & special ID handling

* Update a couple CLI commands to take some alternative options.

* Document the CLI.

* Update the policy list and set-agent-token synopsis
This commit is contained in:
Matt Keeler 2018-10-24 10:24:29 -04:00 committed by GitHub
parent 0dd537e506
commit 8fa3d61d25
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 1426 additions and 43 deletions

View File

@ -305,7 +305,7 @@ func (a *ACL) TokenClone(tokenID string, description string, q *WriteOptions) (*
return nil, nil, fmt.Errorf("Must specify a tokenID for Token Cloning")
}
r := a.c.newRequest("PUT", "/v1/acl/token/clone/"+tokenID)
r := a.c.newRequest("PUT", "/v1/acl/token/"+tokenID+"/clone")
r.setWriteOptions(q)
r.obj = struct{ Description string }{description}
rtt, resp, err := requireOK(a.c.doRequest(r))

View File

@ -4,6 +4,7 @@ import (
"fmt"
"strings"
"github.com/hashicorp/consul/agent/structs"
"github.com/hashicorp/consul/api"
"github.com/mitchellh/cli"
)
@ -73,6 +74,10 @@ func PrintPolicyListEntry(policy *api.ACLPolicyListEntry, ui cli.Ui, showMeta bo
}
func GetTokenIDFromPartial(client *api.Client, partialID string) (string, error) {
if partialID == "anonymous" {
return structs.ACLTokenAnonymousID, nil
}
// the full UUID string was given
if len(partialID) == 36 {
return partialID, nil
@ -101,6 +106,9 @@ func GetTokenIDFromPartial(client *api.Client, partialID string) (string, error)
}
func GetPolicyIDFromPartial(client *api.Client, partialID string) (string, error) {
if partialID == "global-management" {
return structs.ACLPolicyGlobalManagementID, nil
}
// The full UUID string was given
if len(partialID) == 36 {
return partialID, nil
@ -148,8 +156,12 @@ func GetPolicyIDByName(client *api.Client, name string) (string, error) {
}
func GetRulesFromLegacyToken(client *api.Client, tokenID string, isSecret bool) (string, error) {
tokenID, err := GetTokenIDFromPartial(client, tokenID)
if err != nil {
return "", err
}
var token *api.ACLToken
var err error
if isSecret {
qopts := api.QueryOptions{
Token: tokenID,

View File

@ -103,7 +103,7 @@ func (c *cmd) Help() string {
return flags.Usage(c.help, nil)
}
const synopsis = "Interact with the Consul's ACLs"
const synopsis = "Assign tokens for the Consul Agent's usage"
const help = `
Usage: consul acl set-agent-token [options] TYPE TOKEN

View File

@ -32,12 +32,15 @@ type cmd struct {
fromToken string
tokenIsSecret bool
showMeta bool
testStdin io.Reader
}
func (c *cmd) init() {
c.flags = flag.NewFlagSet("", flag.ContinueOnError)
c.flags.BoolVar(&c.showMeta, "meta", false, "Indicates that policy metadata such "+
"as the content hash and raft indices should be show for each entry")
c.flags.StringVar(&c.name, "name", "", "The new policies name. This flag is required.")
c.flags.StringVar(&c.description, "description", "", "A description of the policy")
c.flags.Var((*flags.AppendSliceValue)(&c.datacenters), "valid-datacenter", "Datacenter "+
@ -116,7 +119,7 @@ func (c *cmd) Run(args []string) int {
return 1
}
aclhelpers.PrintPolicy(policy, c.UI, false)
aclhelpers.PrintPolicy(policy, c.UI, c.showMeta)
return 0
}
@ -139,15 +142,15 @@ Usage: consul acl policy create -name NAME [options]
Create a new policy:
$ consul acl policy create -name new-policy \
-description This is an example policy \
-datacenter dc1 \
-datacenter dc2 \
-rules @rules.hcl
$ consul acl policy create -name new-policy \
-description This is an example policy \
-datacenter dc1 \
-datacenter dc2 \
-rules @rules.hcl
Creation a policy from a legacy token:
$ consul acl policy create -name legacy-policy \
-description Token Converted to Policy \
-description Token Converted to Policy \
-from-token c1e34113-e7ab-4451-b1a6-336ddcc58fc6
`

View File

@ -87,12 +87,12 @@ Usage: consul acl policy delete [options] -id POLICY
Deletes an ACL policy by providing either the ID or a unique ID prefix.
Delete by prefix:
Delete by prefix:
$ consul acl policy delete -id b6b85
$ consul acl policy delete -id b6b85
Delete by full ID:
Delete by full ID:
$ consul acl policy delete -id b6b856da-5193-4e78-845a-7d61ca8371ba
$ consul acl policy delete -id b6b856da-5193-4e78-845a-7d61ca8371ba
`

View File

@ -67,11 +67,13 @@ func (c *cmd) Help() string {
return flags.Usage(c.help, nil)
}
const synopsis = "Delete an ACL Policy"
const synopsis = "Lists ACL Policies"
const help = `
Usage: consul acl policy list [options]
Lists all the ACL policies
$ consul acl policy list
Example:
$ consul acl policy list
`

View File

@ -23,10 +23,13 @@ type cmd struct {
policyID string
policyName string
showMeta bool
}
func (c *cmd) init() {
c.flags = flag.NewFlagSet("", flag.ContinueOnError)
c.flags.BoolVar(&c.showMeta, "meta", false, "Indicates that policy metadata such "+
"as the content hash and raft indices should be show for each entry")
c.flags.StringVar(&c.policyID, "id", "", "The ID of the policy to read. "+
"It may be specified as a unique ID prefix but will error if the prefix "+
"matches multiple policy IDs")
@ -69,7 +72,7 @@ func (c *cmd) Run(args []string) int {
c.UI.Error(fmt.Sprintf("Error reading policy %q: %v", policyID, err))
return 1
}
acl.PrintPolicy(policy, c.UI, true)
acl.PrintPolicy(policy, c.UI, c.showMeta)
return 0
}

View File

@ -33,12 +33,14 @@ type cmd struct {
rulesSet bool
rules string
noMerge bool
testStdin io.Reader
showMeta bool
testStdin io.Reader
}
func (c *cmd) init() {
c.flags = flag.NewFlagSet("", flag.ContinueOnError)
c.flags.BoolVar(&c.showMeta, "meta", false, "Indicates that policy metadata such "+
"as the content hash and raft indices should be show for each entry")
c.flags.StringVar(&c.policyID, "id", "", "The ID of the policy to update. "+
"It may be specified as a unique ID prefix but will error if the prefix "+
"matches multiple policy IDs")
@ -145,7 +147,7 @@ func (c *cmd) Run(args []string) int {
}
c.UI.Info(fmt.Sprintf("Policy updated successfully"))
acl.PrintPolicy(policy, c.UI, true)
acl.PrintPolicy(policy, c.UI, c.showMeta)
return 0
}
@ -154,7 +156,7 @@ func (c *cmd) Synopsis() string {
}
func (c *cmd) Help() string {
return flags.Usage(help, nil)
return flags.Usage(c.help, nil)
}
const synopsis = "Update an ACL Policy"

View File

@ -33,6 +33,10 @@ type cmd struct {
func (c *cmd) init() {
c.flags = flag.NewFlagSet("", flag.ContinueOnError)
c.flags.BoolVar(&c.tokenAccessor, "token-accessor", false, "Specifies that "+
"the TRANSLATE argument refers to a ACL token SecretID. "+
"The rules to translate will then be read from the retrieved token")
c.flags.BoolVar(&c.tokenSecret, "token-secret", false,
"Specifies that the TRANSLATE argument refers to a ACL token SecretID. "+
"The rules to translate will then be read from the retrieved token")
@ -54,7 +58,7 @@ func (c *cmd) Run(args []string) int {
return 1
}
if c.tokenSecret {
if c.tokenSecret || c.tokenAccessor {
client, err := c.http.APIClient()
if err != nil {
c.UI.Error(fmt.Sprintf("Error connecting to Consul Agent: %s", err))

View File

@ -0,0 +1,92 @@
package tokenclone
import (
"flag"
"fmt"
"github.com/hashicorp/consul/command/acl"
"github.com/hashicorp/consul/command/flags"
"github.com/mitchellh/cli"
)
func New(ui cli.Ui) *cmd {
c := &cmd{UI: ui}
c.init()
return c
}
type cmd struct {
UI cli.Ui
flags *flag.FlagSet
http *flags.HTTPFlags
help string
tokenID string
description string
}
func (c *cmd) init() {
c.flags = flag.NewFlagSet("", flag.ContinueOnError)
c.flags.StringVar(&c.tokenID, "id", "", "The Accessor ID of the token to clone. "+
"It may be specified as a unique ID prefix but will error if the prefix "+
"matches multiple token Accessor IDs. The special value of 'anonymous' may "+
"be provided instead of the anonymous tokens accessor ID")
c.flags.StringVar(&c.description, "description", "", "A description of the new cloned token")
c.http = &flags.HTTPFlags{}
flags.Merge(c.flags, c.http.ClientFlags())
flags.Merge(c.flags, c.http.ServerFlags())
c.help = flags.Usage(help, c.flags)
}
func (c *cmd) Run(args []string) int {
if err := c.flags.Parse(args); err != nil {
return 1
}
if c.tokenID == "" {
c.UI.Error(fmt.Sprintf("Cannot update a token without specifying the -id parameter"))
return 1
}
client, err := c.http.APIClient()
if err != nil {
c.UI.Error(fmt.Sprintf("Error connecting to Consul agent: %s", err))
return 1
}
tokenID, err := acl.GetTokenIDFromPartial(client, c.tokenID)
if err != nil {
c.UI.Error(fmt.Sprintf("Error determining token ID: %v", err))
return 1
}
token, _, err := client.ACL().TokenClone(tokenID, c.description, nil)
if err != nil {
c.UI.Error(fmt.Sprintf("Error cloning token: %v", err))
return 1
}
c.UI.Info("Token cloned successfully.")
acl.PrintToken(token, c.UI, false)
return 0
}
func (c *cmd) Synopsis() string {
return synopsis
}
func (c *cmd) Help() string {
return flags.Usage(c.help, nil)
}
const synopsis = "Clone an ACL Token"
const help = `
Usage: consul acl token clone [options]
This command will clone a token. When cloning an alternate description may be given
for use with the new token.
Example:
$ consul acl token clone -id abcd -description "replication"
`

View File

@ -0,0 +1,168 @@
package tokenclone
import (
"os"
"regexp"
"strconv"
"strings"
"testing"
"github.com/hashicorp/consul/agent"
"github.com/hashicorp/consul/api"
"github.com/hashicorp/consul/logger"
"github.com/hashicorp/consul/testrpc"
"github.com/hashicorp/consul/testutil"
"github.com/mitchellh/cli"
"github.com/stretchr/testify/require"
)
func parseCloneOutput(t *testing.T, output string) *api.ACLToken {
// This will only work for non-legacy tokens
re := regexp.MustCompile("Token cloned successfully.\n" +
"AccessorID: ([a-zA-Z0-9\\-]{36})\n" +
"SecretID: ([a-zA-Z0-9\\-]{36})\n" +
"Description: ([^\n]*)\n" +
"Local: (true|false)\n" +
"Create Time: ([^\n]+)\n" +
"Policies:\n" +
"( [a-zA-Z0-9\\-]{36} - [^\n]+\n)*")
submatches := re.FindStringSubmatch(output)
require.Lenf(t, submatches, 7, "Didn't match: %q", output)
local, err := strconv.ParseBool(submatches[4])
require.NoError(t, err)
token := &api.ACLToken{
AccessorID: submatches[1],
SecretID: submatches[2],
Description: submatches[3],
Local: local,
}
if len(submatches[6]) > 0 {
policyRe := regexp.MustCompile(" ([a-zA-Z0-9\\-]{36}) - ([^\n]+)")
for _, m := range policyRe.FindAllStringSubmatch(submatches[6], -1) {
token.Policies = append(token.Policies, &api.ACLTokenPolicyLink{ID: m[1], Name: m[2]})
}
}
return token
}
func TestTokenCloneCommand_noTabs(t *testing.T) {
t.Parallel()
if strings.ContainsRune(New(cli.NewMockUi()).Help(), '\t') {
t.Fatal("help has tabs")
}
}
func TestTokenCloneCommand(t *testing.T) {
t.Parallel()
req := require.New(t)
testDir := testutil.TempDir(t, "acl")
defer os.RemoveAll(testDir)
a := agent.NewTestAgent(t.Name(), `
primary_datacenter = "dc1"
acl {
enabled = true
tokens {
master = "root"
}
}`)
a.Agent.LogWriter = logger.NewLogWriter(512)
defer a.Shutdown()
testrpc.WaitForLeader(t, a.RPC, "dc1")
// Create a policy
client := a.Client()
_, _, err := client.ACL().PolicyCreate(
&api.ACLPolicy{Name: "test-policy"},
&api.WriteOptions{Token: "root"},
)
req.NoError(err)
// create a token
token, _, err := client.ACL().TokenCreate(
&api.ACLToken{Description: "test", Policies: []*api.ACLTokenPolicyLink{&api.ACLTokenPolicyLink{Name: "test-policy"}}},
&api.WriteOptions{Token: "root"},
)
req.NoError(err)
// clone with description
t.Run("Description", func(t *testing.T) {
ui := cli.NewMockUi()
cmd := New(ui)
args := []string{
"-http-addr=" + a.HTTPAddr(),
"-id=" + token.AccessorID,
"-token=root",
"-description=test cloned",
}
code := cmd.Run(args)
req.Empty(ui.ErrorWriter.String())
req.Equal(code, 0)
cloned := parseCloneOutput(t, ui.OutputWriter.String())
req.Equal("test cloned", cloned.Description)
req.Len(cloned.Policies, 1)
apiToken, _, err := client.ACL().TokenRead(
cloned.AccessorID,
&api.QueryOptions{Token: "root"},
)
req.NoError(err)
req.NotNil(apiToken)
req.Equal(cloned.AccessorID, apiToken.AccessorID)
req.Equal(cloned.SecretID, apiToken.SecretID)
req.Equal(cloned.Description, apiToken.Description)
req.Equal(cloned.Local, apiToken.Local)
req.Equal(cloned.Policies, apiToken.Policies)
})
// clone without description
t.Run("Without Description", func(t *testing.T) {
ui := cli.NewMockUi()
cmd := New(ui)
args := []string{
"-http-addr=" + a.HTTPAddr(),
"-id=" + token.AccessorID,
"-token=root",
}
code := cmd.Run(args)
req.Equal(code, 0)
req.Empty(ui.ErrorWriter.String())
cloned := parseCloneOutput(t, ui.OutputWriter.String())
req.Equal("test", cloned.Description)
req.Len(cloned.Policies, 1)
apiToken, _, err := client.ACL().TokenRead(
cloned.AccessorID,
&api.QueryOptions{Token: "root"},
)
req.NoError(err)
req.NotNil(apiToken)
req.Equal(cloned.AccessorID, apiToken.AccessorID)
req.Equal(cloned.SecretID, apiToken.SecretID)
req.Equal(cloned.Description, apiToken.Description)
req.Equal(cloned.Local, apiToken.Local)
req.Equal(cloned.Policies, apiToken.Policies)
})
}

View File

@ -26,10 +26,13 @@ type cmd struct {
policyNames []string
description string
local bool
showMeta bool
}
func (c *cmd) init() {
c.flags = flag.NewFlagSet("", flag.ContinueOnError)
c.flags.BoolVar(&c.showMeta, "meta", false, "Indicates that token metadata such "+
"as the content hash and raft indices should be shown for each entry")
c.flags.BoolVar(&c.local, "local", false, "Create this as a datacenter local token")
c.flags.StringVar(&c.description, "description", "", "A description of the token")
c.flags.Var((*flags.AppendSliceValue)(&c.policyIDs), "policy-id", "ID of a "+
@ -84,7 +87,7 @@ func (c *cmd) Run(args []string) int {
return 1
}
acl.PrintToken(token, c.UI, false)
acl.PrintToken(token, c.UI, c.showMeta)
return 0
}

View File

@ -27,7 +27,7 @@ type cmd struct {
func (c *cmd) init() {
c.flags = flag.NewFlagSet("", flag.ContinueOnError)
c.flags.BoolVar(&c.showMeta, "meta", false, "Indicates that token metadata such "+
"as the content hash and raft indices should be show for each entry")
"as the content hash and Raft indices should be shown for each entry")
c.http = &flags.HTTPFlags{}
flags.Merge(c.flags, c.http.ClientFlags())
flags.Merge(c.flags, c.http.ServerFlags())

View File

@ -4,6 +4,7 @@ import (
"flag"
"fmt"
"github.com/hashicorp/consul/api"
"github.com/hashicorp/consul/command/acl"
"github.com/hashicorp/consul/command/flags"
"github.com/mitchellh/cli"
@ -21,11 +22,17 @@ type cmd struct {
http *flags.HTTPFlags
help string
tokenID string
tokenID string
self bool
showMeta bool
}
func (c *cmd) init() {
c.flags = flag.NewFlagSet("", flag.ContinueOnError)
c.flags.BoolVar(&c.showMeta, "meta", false, "Indicates that token metadata such "+
"as the content hash and Raft indices should be shown for each entry")
c.flags.BoolVar(&c.self, "self", false, "Indicates that the current HTTP token "+
"should be read by secret ID instead of expecting a -id option")
c.flags.StringVar(&c.tokenID, "id", "", "The Accessor ID of the token to read. "+
"It may be specified as a unique ID prefix but will error if the prefix "+
"matches multiple token Accessor IDs")
@ -40,7 +47,7 @@ func (c *cmd) Run(args []string) int {
return 1
}
if c.tokenID == "" {
if c.tokenID == "" && !c.self {
c.UI.Error(fmt.Sprintf("Must specify the -id parameter"))
return 1
}
@ -51,19 +58,28 @@ func (c *cmd) Run(args []string) int {
return 1
}
tokenID, err := acl.GetTokenIDFromPartial(client, c.tokenID)
if err != nil {
c.UI.Error(fmt.Sprintf("Error determining token ID: %v", err))
return 1
var token *api.ACLToken
if !c.self {
tokenID, err := acl.GetTokenIDFromPartial(client, c.tokenID)
if err != nil {
c.UI.Error(fmt.Sprintf("Error determining token ID: %v", err))
return 1
}
token, _, err = client.ACL().TokenRead(tokenID, nil)
if err != nil {
c.UI.Error(fmt.Sprintf("Error reading token %q: %v", tokenID, err))
return 1
}
} else {
token, _, err = client.ACL().TokenReadSelf(nil)
if err != nil {
c.UI.Error(fmt.Sprintf("Error reading token: %v", err))
return 1
}
}
token, _, err := client.ACL().TokenRead(tokenID, nil)
if err != nil {
c.UI.Error(fmt.Sprintf("Error reading token %q: %v", tokenID, err))
return 1
}
acl.PrintToken(token, c.UI, true)
acl.PrintToken(token, c.UI, c.showMeta)
return 0
}

View File

@ -22,16 +22,18 @@ type cmd struct {
http *flags.HTTPFlags
help string
tokenID string
policyIDs []string
policyNames []string
description string
tokenID string
policyIDs []string
policyNames []string
description string
mergePolicies bool
showMeta bool
}
func (c *cmd) init() {
c.flags = flag.NewFlagSet("", flag.ContinueOnError)
c.flags.BoolVar(&c.showMeta, "meta", false, "Indicates that token metadata such "+
"as the content hash and raft indices should be shown for each entry")
c.flags.BoolVar(&c.mergePolicies, "merge-policies", false, "Merge the new policies "+
"with the existing policies")
c.flags.StringVar(&c.tokenID, "id", "", "The Accessor ID of the token to read. "+
@ -140,7 +142,7 @@ func (c *cmd) Run(args []string) int {
}
c.UI.Info("Token updated successfully.")
acl.PrintToken(token, c.UI, true)
acl.PrintToken(token, c.UI, c.showMeta)
return 0
}

View File

@ -12,6 +12,7 @@ import (
aclpupdate "github.com/hashicorp/consul/command/acl/policy/update"
aclrules "github.com/hashicorp/consul/command/acl/rules"
acltoken "github.com/hashicorp/consul/command/acl/token"
acltclone "github.com/hashicorp/consul/command/acl/token/clone"
acltcreate "github.com/hashicorp/consul/command/acl/token/create"
acltdelete "github.com/hashicorp/consul/command/acl/token/delete"
acltlist "github.com/hashicorp/consul/command/acl/token/list"
@ -95,6 +96,7 @@ func init() {
Register("acl set-agent-token", func(ui cli.Ui) (cli.Command, error) { return aclagent.New(ui), nil })
Register("acl token", func(cli.Ui) (cli.Command, error) { return acltoken.New(), nil })
Register("acl token create", func(ui cli.Ui) (cli.Command, error) { return acltcreate.New(ui), nil })
Register("acl token clone", func(ui cli.Ui) (cli.Command, error) { return acltclone.New(ui), nil })
Register("acl token list", func(ui cli.Ui) (cli.Command, error) { return acltlist.New(ui), nil })
Register("acl token read", func(ui cli.Ui) (cli.Command, error) { return acltread.New(ui), nil })
Register("acl token update", func(ui cli.Ui) (cli.Command, error) { return acltupdate.New(ui), nil })

View File

@ -0,0 +1,106 @@
---
layout: "docs"
page_title: "Commands: ACL"
sidebar_current: "docs-commands-acl"
---
# Consul ACLs
Command: `consul acl`
The `acl` command is used to interact with Consul's ACLs via the command
line. It exposes top-level commands for bootstrapping the ACL system,
managing tokens and policies, translating legacy rules, and setting the
tokens for use by an agent.
ACLs are also accessible via the [HTTP API](/api/acl.html).
Bootstrap Consul's ACLs:
```sh
$ consul acl bootstrap
AccessorID: 4d123dff-f460-73c3-02c4-8dd64d136e01
SecretID: 86cddfb9-2760-d947-358d-a2811156bf31
Description: Bootstrap Token (Global Management)
Local: false
Create Time: 2018-10-22 11:27:04.479026 -0400 EDT
Policies:
00000000-0000-0000-0000-000000000001 - global-management
```
Create a policy:
```sh
$ consul acl policy create -name "acl-replication" -description "Token capable of replicating ACL policies" -rules 'acl = "read"'
ID: 35b8ecb0-707c-ee18-2002-81b238b54b38
Name: acl-replication
Description: Token capable of replicating ACL policies
Datacenters:
Rules:
acl = "read"
```
Create a token:
```sh
$ consul acl token create -description "Agent Policy Replication - my-agent" -policy-name "acl-replication"
AccessorID: c24c11aa-4e08-e25c-1a67-705a2e8d75a4
SecretID: e7024f9c-f016-02dd-6217-daedbffb86ac
Description: Agent Policy Replication - my-agent
Local: false
Create Time: 2018-10-22 11:34:49.960482 -0400 EDT
Policies:
35b8ecb0-707c-ee18-2002-81b238b54b38 - acl-replication
```
For more examples, ask for subcommand help or view the subcommand documentation
by clicking on one of the links in the sidebar.
## Usage
Usage: `consul acl <subcommand>`
For the exact documentation for your Consul version, run `consul acl -h` to
view the complete list of subcommands.
```text
Usage: consul acl <subcommand> [options] [args]
This command has subcommands for interacting with Consul's ACLs.
Here are some simple examples, and more detailed examples are available
in the subcommands or the documentation.
Bootstrap ACLs:
$ consul acl bootstrap
List all ACL Tokens:
$ consul acl tokens list
Create a new ACL Policy:
$ consul acl policy create “new-policy” \
-description “This is an example policy” \
-datacenter “dc1” \
-datacenter “dc2” \
-rules @rules.hcl
Set the default agent token:
$ consul acl set-agent-token default 0bc6bc46-f25e-4262-b2d9-ffbe1d96be6f
For more examples, ask for subcommand help or view the documentation.
Subcommands:
bootstrap Bootstrap Consul's ACL system
policy Manage Consul's ACL Policies
set-agent-token Interact with the Consul's ACLs
token Manage Consul's ACL Tokens
translate-rules Translate the legacy rule syntax into the current syntax
```
For more information, examples, and usage about a subcommand, click on the name
of the subcommand in the sidebar or one of the links below:

View File

@ -0,0 +1,39 @@
---
layout: "docs"
page_title: "Commands: ACL Bootstrap"
sidebar_current: "docs-commands-acl-bootstrap"
---
# Consul ACL Bootstrap
Command: `consul acl bootstrap`
The `acl bootstrap` command will request Consul to generate a new token with unlimited privileges to use
for management purposes and output its details. This can only be done once and afterwards bootstrapping
will be disabled. If all tokens are lost and you need to bootstrap again you can follow the bootstrap
reset procedure.
The ACL system can also be bootstrapped via the [HTTP API](/api/acl.html#bootstrap-acls).
## Usage
Usage: `consul acl bootstrap [options]`
#### API Options
<%= partial "docs/commands/http_api_options_client" %>
<%= partial "docs/commands/http_api_options_server" %>
The output looks like this:
```text
AccessorID: 4d123dff-f460-73c3-02c4-8dd64d136e01
SecretID: 86cddfb9-2760-d947-358d-a2811156bf31
Description: Bootstrap Token (Global Management)
Local: false
Create Time: 2018-10-22 11:27:04.479026 -0400 EDT
Policies:
00000000-0000-0000-0000-000000000001 - global-management
```

View File

@ -0,0 +1,433 @@
---
layout: "docs"
page_title: "Commands: ACL Policy Management"
sidebar_current: "docs-commands-acl-policy"
---
# Consul ACL Policies
Command: `consul acl policy`
The `acl policy` command is used to manage Consul's ACL policies. There are
subcommands for the individual operations that can be performed.
* [`create`](#create)
* [`read`](#read)
* [`update`](#update)
* [`delete`](#delete)
* [`list`](#list)
ACL policies are also accessible via the [HTTP API](/api/acl.html).
Usage: `consul acl policy <subcommand> [options] [args]`
-> **Note:** All of the examples show for the subcommands will require a valid Consul token with the appropriate permissions.
Either set the `CONSUL_HTTP_TOKEN` environment variable to the tokens secret ID or pass the secret ID as the value of the `-token`
parameter.
## Identitying Polices
In several of the subcommands a policy will have to be identified to be read, modified or deleted. Those subcommands support
specifying the policy by its ID using the `-id` parameter or by name using the `-name` parameter. When specifying the policy
by its ID a unique policy ID prefix may be specified instead of the entire UUID. As long as it is unique it will be resolved
to the full UUID and used. Additionally builtin policy names will be accepted as the value to the `-id` parameter. Even if
the builtin policies are renamed their original name can be used to operate on them.
Builtin Policies:
| Policy UUID | Policy Name |
| ------------------------------------ | ----------------- |
| 00000000-0000-0000-0000-000000000001 | global-management |
## Common Subcommand Options
All of the `consul acl policy` subcommands support the following options:
<%= partial "docs/commands/http_api_options_client" %>
<%= partial "docs/commands/http_api_options_server" %>
## `create`
Command: `consul acl policy create`
This command creates new policies. The policies rules can either be set explicitly or the
`-from-token` parameter may be used to load the rules from a legacy ACL token. When loading
the rules from an existing legacy ACL token, the rules get translated from the legacy syntax
to the new syntax.
Both the `-rules` and `-from-token` parameter values allow loading the value
from stdin, a file or the raw value. To use stdin pass `-` as the value.
To load the value from a file prefix the value with an `@`. Any other
values will be used directly.
-> **Deprecated:** The `-from-token` and `-token-secret` arguments exist only as a convenience
to make legacy ACL migration easier. These will be removed in a future major release when
support for the legacy ACL system is removed.
### Usage
Usage: `consul acl policy create [options] [args]`
#### Options
* [Common Subcommand Options](#common-subcommand-options)
* `-description=<string>` - A description of the policy.
* `-from-token=<string>` - The legacy token to retrieve the rules for when creating this
policy. When this is specified no other rules should be given.
Similar to the -rules option the token to use can be loaded from
stdin or from a file.
* `-meta` - Indicates that policy metadata such as the content hash and raft
indices should be show for each entry.
* `-name=<string>` - The new policies name. This flag is required.
* `-rules=<string>` - The policy rules. May be prefixed with '@' to indicate that the
value is a file path to load the rules from. '-' may also be given
to indicate that the rules are available on stdin.
* `-token-secret` - Indicates the token provided with -from-token is a SecretID and not
an AccessorID.
* `-valid-datacenter=<value>` - Datacenter that the policy should be valid within.
This flag may be specified multiple times.
### Examples
Create a new policy that is valid in all datacenters:
```sh
$ consul acl policy create -name "acl-replication" -description "Policy capable of replicating ACL policies" -rules 'acl = "read"'
ID: 35b8ecb0-707c-ee18-2002-81b238b54b38
Name: acl-replication
Description: Policy capable of replicating ACL policies
Datacenters:
Rules:
acl = "read"
```
Create a new policy valid only in specific datacenters with rules read from a file:
```sh
$ consul acl policy create -name "replication" -description "Replication" -rules @rules.hcl -valid-datacenter dc1 -valid-datacenter dc2
ID: ca44555b-a2d8-94de-d763-88caffdaf11f
Name: replication
Description: Replication
Datacenters: dc1, dc2
Rules:
acl = "read"
service_prefix "" {
policy = "read"
intentions = "read"
}
```
Create a new policy with rules equivalent to that of a legacy ACL token:
```sh
$ consul acl policy create -name "node-services-read" -from-token 5793a5ce -description "Can read any node and service"
ID: 06acc965-df4b-5a99-58cb-3250930c6324
Name: node-services-read
Description: Can read any node and service
Datacenters:
Rules:
service_prefix "" {
policy = "read"
}
node_prefix "" {
policy = "read"
}
```
## `read`
Command: `consul acl policy read`
This command reads and displays a policies details.
### Usage
Usage: `consul acl policy read [options] [args]`
#### Options
* [Common Subcommand Options](#common-subcommand-options)
* `-id=<string>` - The ID of the policy to read. It may be specified as a unique ID
prefix but will error if the prefix matches multiple policy IDs.
* `-meta` - Indicates that policy metadata such as the content hash and raft
indices should be show for each entry.
* `-name=<string>` - The name of the policy to read.
### Examples
Get policy details:
```sh
$ consul acl policy read -id 00000000-0000-0000-0000-000000000001
ID: 00000000-0000-0000-0000-000000000001
Name: global-management
Description: Builtin Policy that grants unlimited access
Datacenters:
Rules:
acl = "write"
agent_prefix "" {
policy = "write"
}
event_prefix "" {
policy = "write"
}
key_prefix "" {
policy = "write"
}
keyring = "write"
node_prefix "" {
policy = "write"
}
operator = "write"
query_prefix "" {
policy = "write"
}
service_prefix "" {
policy = "write"
intentions = "write"
}
session_prefix "" {
policy = "write"
}
```
Get policy details by name:
```sh
$ consul acl policy read -name "acl-replication"
ID: 35b8ecb0-707c-ee18-2002-81b238b54b38
Name: acl-replication
Description: Token capable of replicating ACL policies
Datacenters:
Rules:
acl = "read"
```
Get policy details (Builtin Policies):
Builtin policies can be accessed by specifying their original name as the value to the `-id` parameter.
```sh
$ consul acl policy read -id global-management
ID: 00000000-0000-0000-0000-000000000001
Name: global-management
Description: Builtin Policy that grants unlimited access
Datacenters:
Hash: b30210b7aba9facd1c57891e3df27669174a08b690cb2905e0797535f75eba69
Create Index: 4
Modify Index: 4
Rules:
acl = "write"
agent_prefix "" {
policy = "write"
}
event_prefix "" {
policy = "write"
}
key_prefix "" {
policy = "write"
}
keyring = "write"
node_prefix "" {
policy = "write"
}
operator = "write"
query_prefix "" {
policy = "write"
}
service_prefix "" {
policy = "write"
intentions = "write"
}
session_prefix "" {
policy = "write"
}
```
## `update`
Command: `consul acl policy update`
This command is used to update a policy. The default operations is to merge the current policy
with those values provided to the command invocation. Therefore to update just one field, only
the `-id` or `-name` options and the option to modify must be provided. Note that renaming
policies requires both the `-id` and `-name` as the new name cannot yet be used to lookup the
policy.
### Usage
Usage: `consul acl policy update [options] [args]`
#### Options
* [Common Subcommand Options](#common-subcommand-options)
* `-description=<string>` - A description of the policy.
* `-id=<string>` - The ID of the policy to update. It may be specified as a
unique ID prefix but will error if the prefix matches multiple policy IDs
* `-meta` - Indicates that policy metadata such as the content hash and raft
indices should be show for each entry
* `-name=<string>` - The policies name.
* `-no-merge` - Do not merge the current policy information with what is provided
to the command. Instead overwrite all fields with the exception of
the policy ID which is immutable.
* `-rules=<string>` - The policy rules. May be prefixed with `@` to indicate that
the value is a file path to load the rules from. `-` may also be given to
indicate that the rules are available on stdin.
* `-valid-datacenter=<value>` - Datacenter that the policy should be valid within.
This flag may be specified multiple times.
### Examples
Update a policy:
```sh
$ consul acl policy update -id 35b8 -name "replication" -description "Policy capable of replication ACL policies and Intentions" -rules @rules.hcl
Policy updated successfully
ID: 35b8ecb0-707c-ee18-2002-81b238b54b38
Name: replication
Description: Policy capable of replication ACL policies and Intentions
Datacenters:
Rules:
acl = "read"
service_prefix "" {
policy = "read"
intentions = "read"
}
```
Rename a policy:
```sh
$ consul acl policy update -id 35b8 -name "dc1-replication"
Policy updated successfully
ID: 35b8ecb0-707c-ee18-2002-81b238b54b38
Name: dc1-replication
Description: Policy capable of replication ACL policies and Intentions
Datacenters: dc1
Rules:
acl = "read"
service_prefix "" {
policy = "read"
intentions = "read"
}
```
## `delete`
Command: `consul acl policy delete`
This command deletes a policy. Policies may be deleted by their ID or by name.
### Usage
Usage: `consul acl policy delete [options]`
#### Options
* [Common Subcommand Options](#common-subcommand-options)
* `-id=<string>` - The ID of the policy to delete. It may be specified as a
unique ID prefix but will error if the prefix matches multiple policy IDs.
* `-name=<string>` - The Name of the policy to delete.
### Examples
Delete a policy:
```sh
$ consul acl policy delete -id 35b8
Policy "35b8ecb0-707c-ee18-2002-81b238b54b38" deleted successfully
```
Delete a policy by name:
```sh
$ consul acl policy delete -name acl-replication
Policy "35b8ecb0-707c-ee18-2002-81b238b54b38" deleted successfully
```
## `list`
Command: `consul acl policy list`
This command lists all policies. By default it will not show metadata.
### Usage
Usage: `consul acl policy list`
#### Options
* [Common Subcommand Options](#common-subcommand-options)
* `-meta` - Indicates that policy metadata such as the content hash and
Raft indices should be shown for each entry.
### Examples
Default listing.
```sh
$ consul acl policy list
global-management:
ID: 00000000-0000-0000-0000-000000000001
Description: Builtin Policy that grants unlimited access
Datacenters:
acl-replication:
ID: 35b8ecb0-707c-ee18-2002-81b238b54b38
Description: Policy capable of replicating ACL policies
Datacenters:
```
Show Metadata.
```sh
$ consul acl policy list -meta
global-management:
ID: 00000000-0000-0000-0000-000000000001
Description: Builtin Policy that grants unlimited access
Datacenters:
Hash: b30210b7aba9facd1c57891e3df27669174a08b690cb2905e0797535f75eba69
Create Index: 4
Modify Index: 4
node-services-read:
ID: 06acc965-df4b-5a99-58cb-3250930c6324
Description: Can read any node and service
Datacenters:
Hash: 19d2a73dcd315506af73bfff1492779a0dc0235066fcac07f432fb2cc3402133
Create Index: 244
Modify Index: 244
acl-replication:
ID: ca44555b-a2d8-94de-d763-88caffdaf11f
Description: Token capable of replicating ACL policies
Datacenters: dc1, dc2
Hash: b94669679cc24e0d064412e4aa90b470b7f900a8e0801f65feaf1f7d716a5390
Create Index: 198
Modify Index: 198
```

View File

@ -0,0 +1,49 @@
---
layout: "docs"
page_title: "Commands: ACL Set Agent Token"
sidebar_current: "docs-commands-acl-set-agent-token"
---
# Consul ACL Set Agent Token
Command: `consul acl set-agent-token`
This command updates the ACL tokens currently in use by the agent. It can be used to introduce
ACL tokens to the agent for the first time, or to update tokens that were initially loaded from
the agent's configuration. Tokens are not persisted, so will need to be updated again if the
agent is restarted.
## Usage
Usage: consul acl set-agent-token [options] TYPE TOKEN
### Token Types
* `default` - The default token is the token that the agent will use for
both internal agent operations and operations initiated by the HTTP
and DNS interfaces when no specific token is provided. If not set the
agent will use the anonymous token.
* `agent` - The token that the agent will use for internal agent operations.
If not given then the default token is used for these operations.
* `master` - This sets the token that can be used to access the Agent APIs in
the event that the ACL datacenter cannot be reached.
* `replication` - This is the token that the agent will use for replication
operations. This token will need to be configured with read access to
whatever data is being replicated.
### API Options
<%= partial "docs/commands/http_api_options_client" %>
<%= partial "docs/commands/http_api_options_server" %>
## Examples
Set the `default` token:
```
$ consul acl set-agent-token default c4d0f8df-3aba-4ab6-a7a0-35b760dc29a1
```

View File

@ -0,0 +1,357 @@
---
layout: "docs"
page_title: "Commands: ACL Token Management"
sidebar_current: "docs-commands-acl-token"
---
# Consul ACL Tokens
Command: `consul acl token`
The `acl token` command is used to manage Consul's ACL tokens. There are
subcommands for the individual operations that can be performed.
* [`create`](#create)
* [`clone`](#clone)
* [`read`](#read)
* [`update`](#update)
* [`delete`](#delete)
* [`list`](#list)
ACL tokens are also accessible via the [HTTP API](/api/acl.html).
Usage: `consul acl token <subcommand> [options] [args]`
-> **Note:** All of the examples show for the subcommands will require a valid Consul token with the appropriate permissions.
Either set the `CONSUL_HTTP_TOKEN` environment variable to the tokens secret ID or pass the secret ID as the value of the `-token`
parameter.
## Identitying Tokens
In several of the subcommands a token will have to be identified to be read, modified or deleted. Those subcommands support
specifying the token by its ID using the `-id` parameter. The ID may be specified as a unique UUID prefix instead of the entire
UUID. As long as it is unique it will be resolve to the full UUID and used. Additionally builtin token names will be accepted as
the value of the `-id`.
Builtin Policies:
| Token UUID | Token Name |
| ------------------------------------ | ----------------- |
| 00000000-0000-0000-0000-000000000002 | anonymous |
## Common Subcommand Options
All of the `consul acl token` subcommands support the following options:
<%= partial "docs/commands/http_api_options_client" %>
<%= partial "docs/commands/http_api_options_server" %>
## `create`
Command: `consul acl token create`
This command creates new tokens. When creating a new token, policies may be linked using
either the `-policy-id` or the `-policy-name options. When specifying policies by IDs you
may use a unique prefix of the UUID as a shortcut for specifying the entire UUID.
### Usage
#### Options
* [Common Subcommand Options](#common-subcommand-options)
* `-description=<string>` - A description of the token.
* `-local` - Create this as a datacenter local token.
* `-policy-id=<value>` - ID of a policy to use for this token. May be specified multiple times.
* `-policy-name=<value>` - Name of a policy to use for this token. May be specified multiple times.
* `-meta` - Indicates that token metadata such as the content hash and raft indices should be shown
for each entry.
### Examples
Create a new token:
```sh
$ consul acl token create -description "Read Nodes and Services" -policy-id 06acc965
AccessorID: 986193b5-e2b5-eb26-6264-b524ea60cc6d
SecretID: ec15675e-2999-d789-832e-8c4794daa8d7
Description: Read Nodes and Services
Local: false
Create Time: 2018-10-22 15:33:39.01789 -0400 EDT
Policies:
06acc965-df4b-5a99-58cb-3250930c6324 - node-services-read
```
Create a new local token:
```sh
$ consul acl token create -description "Read Nodes and Services" -policy-id 06acc965 -local
AccessorID: 4fdf0ec8-d251-3865-079c-7247c974fc50
SecretID: 02143514-abf2-6c23-0aa1-ec2107e68f6b
Description: Read Nodes and Services
Local: true
Create Time: 2018-10-22 15:34:19.330265 -0400 EDT
Policies:
06acc965-df4b-5a99-58cb-3250930c6324 - node-services-read
```
Create a new policy and link with policies by name:
```sh
$ consul acl token create -description "Super User" -policy-name global-management
AccessorID: 59f86a9b-d3b6-166c-32a0-be4ab3f94caa
SecretID: ada7f751-f654-8872-7f93-498e799158b6
Description: Super User
Local: false
Create Time: 2018-10-22 15:35:28.787003 -0400 EDT
Policies:
00000000-0000-0000-0000-000000000001 - global-management
```
## `clone`
Command: `consul acl token clone`
This command clones an existing token.
### Usage
Usage: `consul acl token clone [options]
#### Options
* [Common Subcommand Options](#common-subcommand-options)
* `-description=<string>` - A description of the new cloned token.
* `-id=<string>` - The Accessor ID of the token to clone. It may be specified
as a unique ID prefix but will error if the prefix matches multiple token
Accessor IDs. The special value of 'anonymous' may be provided instead of
the anonymous tokens accessor ID
### Examples
Clone a token:
```sh
$ consul acl token clone -id 59f8 -description "Clone of Super User"
Token cloned successfully.
AccessorID: dcfa52ed-9288-b3ff-056d-255ef69d2d88
SecretID: 0005d17e-5bb2-7e8b-7bfa-15f2eee9ad14
Description: Clone of Super User
Local: false
Create Time: 2018-10-22 16:26:02.909096 -0400 EDT
Policies:
00000000-0000-0000-0000-000000000001 - global-management
```
## `read`
Command: `consul acl token read`
This command reads and displays a token details.
### Usage
Usage: `consul acl token read [options] [args]`
#### Options
* [Common Subcommand Options](#common-subcommand-options)
* `-id=<string>` - The ID of the policy to read. It may be specified as a unique ID
prefix but will error if the prefix matches multiple policy IDs.
* `-meta` - Indicates that policy metadata such as the content hash and raft
indices should be show for each entry.
* `-name=<string>` - The name of the policy to read.
* `-self` - Indicates that the current HTTP token should be read by secret ID
instead of expecting a -id option.
### Examples
Get token details:
```sh
$ consul acl token read -id 986
AccessorID: 986193b5-e2b5-eb26-6264-b524ea60cc6d
SecretID: ec15675e-2999-d789-832e-8c4794daa8d7
Description: Read Nodes and Services
Local: false
Create Time: 2018-10-22 15:33:39.01789 -0400 EDT
Policies:
06acc965-df4b-5a99-58cb-3250930c6324 - node-services-read
```
Get token details using the token secret ID:
```sh
$consul acl token read -self
AccessorID: 4d123dff-f460-73c3-02c4-8dd64d136e01
SecretID: 86cddfb9-2760-d947-358d-a2811156bf31
Description: Bootstrap Token (Global Management)
Local: false
Create Time: 2018-10-22 11:27:04.479026 -0400 EDT
Policies:
00000000-0000-0000-0000-000000000001 - global-management
```
Get token details (Builtin Tokens)
```sh
$ consul acl token read -id anonymous
AccessorID: 00000000-0000-0000-0000-000000000002
SecretID: anonymous
Description: Anonymous Token
Local: false
Create Time: 0001-01-01 00:00:00 +0000 UTC
Policies:
```
## `update`
Command: `consul acl token update`
This command will update a token. Some parts of the token like whether the
token is local to the datacenter cannot be changed.
### Usage
Usage: `consul acl token update [options]`
#### Options
* [Common Subcommand Options](#common-subcommand-options)
* `-description=<string>` - A description of the token
* `-id=<string>` - The Accessor ID of the token to read. It may be specified as a
unique ID prefix but will error if the prefix matches multiple token Accessor IDs
* `-merge-policies` - Merge the new policies with the existing policies
* `-meta` - Indicates that token metadata such as the content hash and Raft indices should be
shown for each entry.
* `-policy-id=<value>` - ID of a policy to use for this token. May be specified multiple times.
* `-policy-name=<value>` - Name of a policy to use for this token. May be specified multiple times.
### Examples
Update the anonymous token:
```sh
$ consul acl token update -id anonymous -policy-id 06acc
Token updated successfully.
AccessorID: 00000000-0000-0000-0000-000000000002
SecretID: anonymous
Description: Anonymous Token
Local: false
Create Time: 0001-01-01 00:00:00 +0000 UTC
Policies:
06acc965-df4b-5a99-58cb-3250930c6324 - node-services-read
```
Update a token description and take the policies from the existing token:
```sh
$ consul acl token update -id 986193 -description "WonderToken" -merge-policies
Token updated successfully.
AccessorID: 986193b5-e2b5-eb26-6264-b524ea60cc6d
SecretID: ec15675e-2999-d789-832e-8c4794daa8d7
Description: WonderToken
Local: false
Create Time: 2018-10-22 15:33:39.01789 -0400 EDT
Policies:
06acc965-df4b-5a99-58cb-3250930c6324 - node-services-read
```
## `delete`
Command: `consul acl token delete`
This command deletes a token.
### Usage
Usage: `consul acl token delete [options]`
#### Options
* [Common Subcommand Options](#common-subcommand-options)
* `-id=<string>` - The ID of the token to delete. It may be specified as a
unique ID prefix but will error if the prefix matches multiple token IDs.
### Examples
Delete a token:
```sh
$ consul acl token delete -id 35b8
Token "35b8ecb0-707c-ee18-2002-81b238b54b38" deleted successfully
```
## `list`
Command: `consul acl token list`
This command lists all tokens. By default it will not show metadata.
### Usage
Usage: `consul acl token list`
#### Options
* [Common Subcommand Options](#common-subcommand-options)
* `-meta` - Indicates that token metadata such as the content hash and
Raft indices should be shown for each entry.
### Examples
Default listing.
```sh
$ consul acl token list
AccessorID: 4d123dff-f460-73c3-02c4-8dd64d136e01
Description: Bootstrap Token (Global Management)
Local: false
Create Time: 2018-10-22 11:27:04.479026 -0400 EDT
Legacy: false
Policies:
00000000-0000-0000-0000-000000000001 - global-management
AccessorID: 59f86a9b-d3b6-166c-32a0-be4ab3f94caa
Description: Super User
Local: false
Create Time: 2018-10-22 15:35:28.787003 -0400 EDT
Legacy: false
Policies:
00000000-0000-0000-0000-000000000001 - global-management
AccessorID: 00000000-0000-0000-0000-000000000002
Description: Anonymous Token
Local: false
Create Time: 0001-01-01 00:00:00 +0000 UTC
Legacy: false
Policies:
06acc965-df4b-5a99-58cb-3250930c6324 - node-services-read
AccessorID: 986193b5-e2b5-eb26-6264-b524ea60cc6d
Description: WonderToken
Local: false
Create Time: 2018-10-22 15:33:39.01789 -0400 EDT
Legacy: false
Policies:
06acc965-df4b-5a99-58cb-3250930c6324 - node-services-read
```

View File

@ -0,0 +1,70 @@
---
layout: "docs"
page_title: "Commands: ACL Translate Rules"
sidebar_current: "docs-commands-acl-translate-rules"
---
-> **Deprecated:** This command exists only as a convenience to make legacy ACL migration easier.
It will be removed in a future major release when support for the legacy ACL system is removed.
# Consul ACL Translate Rules
Command: `consul acl translate-rules`
This command translates the legacy ACL rule syntax into the new syntax.
### Usage
Usage: `consul acl translate rules [options] TRANSLATE`
#### API Options
<%= partial "docs/commands/http_api_options_client" %>
<%= partial "docs/commands/http_api_options_server" %>
#### Command Options
* `TRANSLATE` - The rules to translate. If `-` is used, then
the rules will be read from stdin. If `@` is prefixed to
the value then the value is considered to be a file and
the rules will be read from that file.
* `-token-secret` - Specifies that what the `TRANSLATE` argument
holds is not a rule set but rather the token secret ID of a
legacy ACL token that holds the rule set.
* `-token-accessor` - Specifies that what the `TRANSLATE` argument
holds is not a rule set but rather the token accessor ID of a
legacy ACL token that holds the rule set.
### Examples
Translate rules within a file:
```sh
$ consul acl translate-rules @rules.hcl
```
Translate rules from stdin:
```sh
$ consul acl translate-rules -
```
Translate rules from a string argument:
```sh
$ consul acl translate-rules 'key "" { policy = "write"}'
```
Translate rules for a legacy ACL token using its SecretID passed from stdin:
```sh
$ consul acl translate-rules --token-secret -
```
Translate rules for a legacy ACL token using its AccessorID:
```sh
$ consul acl translate-rules 429cd746-03d5-4bbb-a83a-18b164171c89
```

View File

@ -53,6 +53,26 @@
<li<%= sidebar_current("docs-commands") %>>
<a href="/docs/commands/index.html">Commands (CLI)</a>
<ul class="nav">
<li<%= sidebar_current("docs-commands-acl") %>>
<a href="/docs/commands/acl.html">acl</a>
<ul class="nav">
<li<%= sidebar_current("docs-commands-acl-bootstrap") %>>
<a href="/docs/commands/acl/acl-bootstrap.html">bootstrap</a>
</li>
<li<%= sidebar_current("docs-commands-acl-policy") %>>
<a href="/docs/commands/acl/acl-policy.html">policy</a>
</li>
<li<%= sidebar_current("docs-commands-acl-set-agent-token") %>>
<a href="/docs/commands/acl/acl-set-agent-token.html">set-agent-token</a>
</li>
<li<%= sidebar_current("docs-commands-acl-token") %>>
<a href="/docs/commands/acl/acl-token.html">token</a>
</li>
<li<%= sidebar_current("docs-commands-acl-translate-rules") %>>
<a href="/docs/commands/acl/acl-translate-rules.html">translate-rules</a>
</li>
</ul>
</li>
<li<%= sidebar_current("docs-commands-agent") %>>
<a href="/docs/commands/agent.html">agent</a>
</li>