Skip to content

Commit

Permalink
ACL CLI
Browse files Browse the repository at this point in the history
bootstrap, set-agent-token and policies commands are done

still need to implement token ops.

Also got rid of specifying a policy by name in the api.
  • Loading branch information
mkeeler committed Oct 12, 2018
1 parent 876ef24 commit 46c9ff3
Showing 25 changed files with 1,574 additions and 85 deletions.
52 changes: 14 additions & 38 deletions agent/acl_endpoint.go
Original file line number Diff line number Diff line change
@@ -168,7 +168,7 @@ func (s *HTTPServer) ACLPolicyCRUD(resp http.ResponseWriter, req *http.Request)
return nil, nil
}

var fn func(resp http.ResponseWriter, req *http.Request, policyID string, policyIDType structs.ACLPolicyIDType) (interface{}, error)
var fn func(resp http.ResponseWriter, req *http.Request, policyID string) (interface{}, error)

switch req.Method {
case "GET":
@@ -189,27 +189,13 @@ func (s *HTTPServer) ACLPolicyCRUD(resp http.ResponseWriter, req *http.Request)
return nil, BadRequestError{Reason: "Missing policy ID"}
}

policyIDType := structs.ACLPolicyID

if idType := req.URL.Query().Get("idType"); idType != "" {
switch idType {
case "id":
policyIDType = structs.ACLPolicyID
case "name":
policyIDType = structs.ACLPolicyName
default:
return nil, BadRequestError{Reason: "Invalid value for idType parameter"}
}
}

return fn(resp, req, policyID, policyIDType)
return fn(resp, req, policyID)
}

func (s *HTTPServer) ACLPolicyRead(resp http.ResponseWriter, req *http.Request, policyID string, policyIDType structs.ACLPolicyIDType) (interface{}, error) {
func (s *HTTPServer) ACLPolicyRead(resp http.ResponseWriter, req *http.Request, policyID string) (interface{}, error) {
args := structs.ACLPolicyReadRequest{
Datacenter: s.agent.config.Datacenter,
PolicyID: policyID,
PolicyIDType: policyIDType,
Datacenter: s.agent.config.Datacenter,
PolicyID: policyID,
}
if done := s.parse(resp, req, &args.Datacenter, &args.QueryOptions); done {
return nil, nil
@@ -233,7 +219,7 @@ func (s *HTTPServer) ACLPolicyRead(resp http.ResponseWriter, req *http.Request,
}

func (s *HTTPServer) ACLPolicyCreate(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
return s.ACLPolicyWrite(resp, req, "", structs.ACLPolicyID)
return s.ACLPolicyWrite(resp, req, "")
}

// fixCreateTime is used to help in decoding the CreateTime attribute from
@@ -257,7 +243,7 @@ func fixCreateTime(raw interface{}) error {
return nil
}

func (s *HTTPServer) ACLPolicyWrite(resp http.ResponseWriter, req *http.Request, policyID string, policyIDType structs.ACLPolicyIDType) (interface{}, error) {
func (s *HTTPServer) ACLPolicyWrite(resp http.ResponseWriter, req *http.Request, policyID string) (interface{}, error) {
args := structs.ACLPolicyUpsertRequest{
Datacenter: s.agent.config.Datacenter,
}
@@ -270,19 +256,10 @@ func (s *HTTPServer) ACLPolicyWrite(resp http.ResponseWriter, req *http.Request,
args.Policy.Syntax = acl.SyntaxCurrent

// TODO (ACL-V2) - Should we allow not specifying the ID in the payload when its specified in the URL
switch policyIDType {
case structs.ACLPolicyID:
if policyID != "" && args.Policy.ID != "" && args.Policy.ID != policyID {
return nil, BadRequestError{Reason: "Policy ID in URL and payload do not match"}
} else if args.Policy.ID == "" {
args.Policy.ID = policyID
}
case structs.ACLPolicyName:
if policyID != "" && args.Policy.Name != "" && args.Policy.Name != policyID {
return nil, BadRequestError{Reason: "Policy Name in URL and payload do not match"}
} else if args.Policy.Name == "" {
args.Policy.Name = ""
}
if policyID != "" && args.Policy.ID != "" && args.Policy.ID != policyID {
return nil, BadRequestError{Reason: "Policy ID in URL and payload do not match"}
} else if args.Policy.ID == "" {
args.Policy.ID = policyID
}

var out structs.ACLPolicy
@@ -293,11 +270,10 @@ func (s *HTTPServer) ACLPolicyWrite(resp http.ResponseWriter, req *http.Request,
return &out, nil
}

func (s *HTTPServer) ACLPolicyDelete(resp http.ResponseWriter, req *http.Request, policyID string, policyIDType structs.ACLPolicyIDType) (interface{}, error) {
func (s *HTTPServer) ACLPolicyDelete(resp http.ResponseWriter, req *http.Request, policyID string) (interface{}, error) {
args := structs.ACLPolicyDeleteRequest{
Datacenter: s.agent.config.Datacenter,
PolicyID: policyID,
PolicyIDType: policyIDType,
Datacenter: s.agent.config.Datacenter,
PolicyID: policyID,
}
s.parseToken(req, &args.Token)

23 changes: 3 additions & 20 deletions agent/consul/acl_endpoint.go
Original file line number Diff line number Diff line change
@@ -557,14 +557,7 @@ func (a *ACL) PolicyRead(args *structs.ACLPolicyReadRequest, reply *structs.ACLP

return a.srv.blockingQuery(&args.QueryOptions, &reply.QueryMeta,
func(ws memdb.WatchSet, state *state.Store) error {
var index uint64
var policy *structs.ACLPolicy
var err error
if args.PolicyIDType == structs.ACLPolicyID {
index, policy, err = state.ACLPolicyGetByID(ws, args.PolicyID)
} else {
index, policy, err = state.ACLPolicyGetByName(ws, args.PolicyID)
}
index, policy, err := state.ACLPolicyGetByID(ws, args.PolicyID)

if err != nil {
return err
@@ -740,16 +733,7 @@ func (a *ACL) PolicyDelete(args *structs.ACLPolicyDeleteRequest, reply *string)
return acl.ErrPermissionDenied
}

var policy *structs.ACLPolicy
var err error
switch args.PolicyIDType {
case structs.ACLPolicyID:
_, policy, err = a.srv.fsm.State().ACLPolicyGetByID(nil, args.PolicyID)
case structs.ACLPolicyName:
_, policy, err = a.srv.fsm.State().ACLPolicyGetByName(nil, args.PolicyID)
default:
return fmt.Errorf("Invalid policy id type")
}
_, policy, err := a.srv.fsm.State().ACLPolicyGetByID(nil, args.PolicyID)
if err != nil {
return err
}
@@ -763,8 +747,7 @@ func (a *ACL) PolicyDelete(args *structs.ACLPolicyDeleteRequest, reply *string)
}

req := structs.ACLPolicyBatchDeleteRequest{
PolicyIDs: []string{args.PolicyID},
PolicyIDType: args.PolicyIDType,
PolicyIDs: []string{args.PolicyID},
}

resp, err := a.srv.raftApply(structs.ACLPolicyDeleteRequestType, &req)
4 changes: 1 addition & 3 deletions agent/consul/acl_replication.go
Original file line number Diff line number Diff line change
@@ -66,9 +66,7 @@ func (s *Server) deleteLocalACLPolicies(deletions []string, stopCh <-chan struct
defer ticker.Stop()

for i := 0; i < len(deletions); i += aclBatchDeleteSize {
req := structs.ACLPolicyBatchDeleteRequest{
PolicyIDType: structs.ACLPolicyID,
}
req := structs.ACLPolicyBatchDeleteRequest{}

if i+aclBatchDeleteSize > len(deletions) {
req.PolicyIDs = deletions[i:]
2 changes: 1 addition & 1 deletion agent/consul/fsm/commands_oss.go
Original file line number Diff line number Diff line change
@@ -392,5 +392,5 @@ func (c *FSM) applyACLPolicyDeleteOperation(buf []byte, index uint64) interface{
defer metrics.MeasureSinceWithLabels([]string{"fsm", "acl", "policy"}, time.Now(),
[]metrics.Label{{Name: "op", Value: "delete"}})

return c.state.ACLPoliciesDelete(index, req.PolicyIDs, req.PolicyIDType)
return c.state.ACLPoliciesDelete(index, req.PolicyIDs)
}
9 changes: 2 additions & 7 deletions agent/consul/state/acl.go
Original file line number Diff line number Diff line change
@@ -746,17 +746,12 @@ func (s *Store) ACLPolicyDeleteByName(idx uint64, name string) error {
return s.aclPolicyDelete(idx, name, "name")
}

func (s *Store) ACLPoliciesDelete(idx uint64, policyIDs []string, idType structs.ACLPolicyIDType) error {
func (s *Store) ACLPoliciesDelete(idx uint64, policyIDs []string) error {
tx := s.db.Txn(true)
defer tx.Abort()

index := "id"
if idType == structs.ACLPolicyName {
index = "name"
}

for _, policyID := range policyIDs {
s.aclPolicyDeleteTxn(tx, idx, policyID, index)
s.aclPolicyDeleteTxn(tx, idx, policyID, "id")
}

if err := indexUpdateMaxTxn(tx, idx, "acl-policies"); err != nil {
13 changes: 5 additions & 8 deletions agent/structs/acl.go
Original file line number Diff line number Diff line change
@@ -656,9 +656,8 @@ func (r *ACLPolicyUpsertRequest) RequestDatacenter() string {

// ACLPolicyDeleteRequest is used at the RPC layer deletion requests
type ACLPolicyDeleteRequest struct {
PolicyID string // The id of the policy to delete
PolicyIDType ACLPolicyIDType // Whether the PolicyIDs are Names or IDs
Datacenter string // The datacenter to perform the request within
PolicyID string // The id of the policy to delete
Datacenter string // The datacenter to perform the request within
WriteRequest
}

@@ -668,9 +667,8 @@ func (r *ACLPolicyDeleteRequest) RequestDatacenter() string {

// ACLPolicyReadRequest is used at the RPC layer to perform policy read operations
type ACLPolicyReadRequest struct {
PolicyID string // id used for the policy lookup
PolicyIDType ACLPolicyIDType // The type of id used to lookup the token
Datacenter string // The datacenter to perform the request within
PolicyID string // id used for the policy lookup
Datacenter string // The datacenter to perform the request within
QueryOptions
}

@@ -730,6 +728,5 @@ type ACLPolicyBatchUpsertRequest struct {
//
// This is particularly useful during replication
type ACLPolicyBatchDeleteRequest struct {
PolicyIDs []string
PolicyIDType ACLPolicyIDType
PolicyIDs []string
}
10 changes: 2 additions & 8 deletions api/acl.go
Original file line number Diff line number Diff line change
@@ -469,12 +469,9 @@ func (a *ACL) PolicyUpdate(policy *ACLPolicy, q *WriteOptions) (*ACLPolicy, *Wri
return &out, wm, nil
}

func (a *ACL) PolicyDelete(policyID string, byName bool, q *WriteOptions) (*WriteMeta, error) {
func (a *ACL) PolicyDelete(policyID string, q *WriteOptions) (*WriteMeta, error) {
r := a.c.newRequest("DELETE", "/v1/acl/policy/"+policyID)
r.setWriteOptions(q)
if byName {
r.params.Set("idType", "name")
}
rtt, resp, err := requireOK(a.c.doRequest(r))
if err != nil {
return nil, err
@@ -485,12 +482,9 @@ func (a *ACL) PolicyDelete(policyID string, byName bool, q *WriteOptions) (*Writ
return wm, nil
}

func (a *ACL) PolicyRead(policyID string, byName bool, q *QueryOptions) (*ACLPolicy, *QueryMeta, error) {
func (a *ACL) PolicyRead(policyID string, q *QueryOptions) (*ACLPolicy, *QueryMeta, error) {
r := a.c.newRequest("GET", "/v1/acl/policy/"+policyID)
r.setQueryOptions(q)
if byName {
r.params.Set("idType", "name")
}
rtt, resp, err := requireOK(a.c.doRequest(r))
if err != nil {
return nil, nil, err
55 changes: 55 additions & 0 deletions command/acl/acl.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package acl

import (
"github.com/hashicorp/consul/command/flags"
"github.com/mitchellh/cli"
)

func New() *cmd {
return &cmd{}
}

type cmd struct{}

func (c *cmd) Run(args []string) int {
return cli.RunResultHelp
}

func (c *cmd) Synopsis() string {
return synopsis
}

func (c *cmd) Help() string {
return flags.Usage(help, nil)
}

const synopsis = "Interact with the Consul's ACLs"
const help = `
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.
`
Loading

0 comments on commit 46c9ff3

Please sign in to comment.