github.com/sl1pm4t/consul@v1.4.5-0.20190325224627-74c31c540f9c/api/acl.go (about)

     1  package api
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"io/ioutil"
     7  	"time"
     8  )
     9  
    10  const (
    11  	// ACLClientType is the client type token
    12  	ACLClientType = "client"
    13  
    14  	// ACLManagementType is the management type token
    15  	ACLManagementType = "management"
    16  )
    17  
    18  type ACLTokenPolicyLink struct {
    19  	ID   string
    20  	Name string
    21  }
    22  
    23  // ACLToken represents an ACL Token
    24  type ACLToken struct {
    25  	CreateIndex uint64
    26  	ModifyIndex uint64
    27  	AccessorID  string
    28  	SecretID    string
    29  	Description string
    30  	Policies    []*ACLTokenPolicyLink
    31  	Local       bool
    32  	CreateTime  time.Time `json:",omitempty"`
    33  	Hash        []byte    `json:",omitempty"`
    34  
    35  	// DEPRECATED (ACL-Legacy-Compat)
    36  	// Rules will only be present for legacy tokens returned via the new APIs
    37  	Rules string `json:",omitempty"`
    38  }
    39  
    40  type ACLTokenListEntry struct {
    41  	CreateIndex uint64
    42  	ModifyIndex uint64
    43  	AccessorID  string
    44  	Description string
    45  	Policies    []*ACLTokenPolicyLink
    46  	Local       bool
    47  	CreateTime  time.Time
    48  	Hash        []byte
    49  	Legacy      bool
    50  }
    51  
    52  // ACLEntry is used to represent a legacy ACL token
    53  // The legacy tokens are deprecated.
    54  type ACLEntry struct {
    55  	CreateIndex uint64
    56  	ModifyIndex uint64
    57  	ID          string
    58  	Name        string
    59  	Type        string
    60  	Rules       string
    61  }
    62  
    63  // ACLReplicationStatus is used to represent the status of ACL replication.
    64  type ACLReplicationStatus struct {
    65  	Enabled              bool
    66  	Running              bool
    67  	SourceDatacenter     string
    68  	ReplicationType      string
    69  	ReplicatedIndex      uint64
    70  	ReplicatedTokenIndex uint64
    71  	LastSuccess          time.Time
    72  	LastError            time.Time
    73  }
    74  
    75  // ACLPolicy represents an ACL Policy.
    76  type ACLPolicy struct {
    77  	ID          string
    78  	Name        string
    79  	Description string
    80  	Rules       string
    81  	Datacenters []string
    82  	Hash        []byte
    83  	CreateIndex uint64
    84  	ModifyIndex uint64
    85  }
    86  
    87  type ACLPolicyListEntry struct {
    88  	ID          string
    89  	Name        string
    90  	Description string
    91  	Datacenters []string
    92  	Hash        []byte
    93  	CreateIndex uint64
    94  	ModifyIndex uint64
    95  }
    96  
    97  // ACL can be used to query the ACL endpoints
    98  type ACL struct {
    99  	c *Client
   100  }
   101  
   102  // ACL returns a handle to the ACL endpoints
   103  func (c *Client) ACL() *ACL {
   104  	return &ACL{c}
   105  }
   106  
   107  // Bootstrap is used to perform a one-time ACL bootstrap operation on a cluster
   108  // to get the first management token.
   109  func (a *ACL) Bootstrap() (*ACLToken, *WriteMeta, error) {
   110  	r := a.c.newRequest("PUT", "/v1/acl/bootstrap")
   111  	rtt, resp, err := requireOK(a.c.doRequest(r))
   112  	if err != nil {
   113  		return nil, nil, err
   114  	}
   115  	defer resp.Body.Close()
   116  
   117  	wm := &WriteMeta{RequestTime: rtt}
   118  	var out ACLToken
   119  	if err := decodeBody(resp, &out); err != nil {
   120  		return nil, nil, err
   121  	}
   122  	return &out, wm, nil
   123  }
   124  
   125  // Create is used to generate a new token with the given parameters
   126  //
   127  // Deprecated: Use TokenCreate instead.
   128  func (a *ACL) Create(acl *ACLEntry, q *WriteOptions) (string, *WriteMeta, error) {
   129  	r := a.c.newRequest("PUT", "/v1/acl/create")
   130  	r.setWriteOptions(q)
   131  	r.obj = acl
   132  	rtt, resp, err := requireOK(a.c.doRequest(r))
   133  	if err != nil {
   134  		return "", nil, err
   135  	}
   136  	defer resp.Body.Close()
   137  
   138  	wm := &WriteMeta{RequestTime: rtt}
   139  	var out struct{ ID string }
   140  	if err := decodeBody(resp, &out); err != nil {
   141  		return "", nil, err
   142  	}
   143  	return out.ID, wm, nil
   144  }
   145  
   146  // Update is used to update the rules of an existing token
   147  //
   148  // Deprecated: Use TokenUpdate instead.
   149  func (a *ACL) Update(acl *ACLEntry, q *WriteOptions) (*WriteMeta, error) {
   150  	r := a.c.newRequest("PUT", "/v1/acl/update")
   151  	r.setWriteOptions(q)
   152  	r.obj = acl
   153  	rtt, resp, err := requireOK(a.c.doRequest(r))
   154  	if err != nil {
   155  		return nil, err
   156  	}
   157  	defer resp.Body.Close()
   158  
   159  	wm := &WriteMeta{RequestTime: rtt}
   160  	return wm, nil
   161  }
   162  
   163  // Destroy is used to destroy a given ACL token ID
   164  //
   165  // Deprecated: Use TokenDelete instead.
   166  func (a *ACL) Destroy(id string, q *WriteOptions) (*WriteMeta, error) {
   167  	r := a.c.newRequest("PUT", "/v1/acl/destroy/"+id)
   168  	r.setWriteOptions(q)
   169  	rtt, resp, err := requireOK(a.c.doRequest(r))
   170  	if err != nil {
   171  		return nil, err
   172  	}
   173  	resp.Body.Close()
   174  
   175  	wm := &WriteMeta{RequestTime: rtt}
   176  	return wm, nil
   177  }
   178  
   179  // Clone is used to return a new token cloned from an existing one
   180  //
   181  // Deprecated: Use TokenClone instead.
   182  func (a *ACL) Clone(id string, q *WriteOptions) (string, *WriteMeta, error) {
   183  	r := a.c.newRequest("PUT", "/v1/acl/clone/"+id)
   184  	r.setWriteOptions(q)
   185  	rtt, resp, err := requireOK(a.c.doRequest(r))
   186  	if err != nil {
   187  		return "", nil, err
   188  	}
   189  	defer resp.Body.Close()
   190  
   191  	wm := &WriteMeta{RequestTime: rtt}
   192  	var out struct{ ID string }
   193  	if err := decodeBody(resp, &out); err != nil {
   194  		return "", nil, err
   195  	}
   196  	return out.ID, wm, nil
   197  }
   198  
   199  // Info is used to query for information about an ACL token
   200  //
   201  // Deprecated: Use TokenRead instead.
   202  func (a *ACL) Info(id string, q *QueryOptions) (*ACLEntry, *QueryMeta, error) {
   203  	r := a.c.newRequest("GET", "/v1/acl/info/"+id)
   204  	r.setQueryOptions(q)
   205  	rtt, resp, err := requireOK(a.c.doRequest(r))
   206  	if err != nil {
   207  		return nil, nil, err
   208  	}
   209  	defer resp.Body.Close()
   210  
   211  	qm := &QueryMeta{}
   212  	parseQueryMeta(resp, qm)
   213  	qm.RequestTime = rtt
   214  
   215  	var entries []*ACLEntry
   216  	if err := decodeBody(resp, &entries); err != nil {
   217  		return nil, nil, err
   218  	}
   219  	if len(entries) > 0 {
   220  		return entries[0], qm, nil
   221  	}
   222  	return nil, qm, nil
   223  }
   224  
   225  // List is used to get all the ACL tokens
   226  //
   227  // Deprecated: Use TokenList instead.
   228  func (a *ACL) List(q *QueryOptions) ([]*ACLEntry, *QueryMeta, error) {
   229  	r := a.c.newRequest("GET", "/v1/acl/list")
   230  	r.setQueryOptions(q)
   231  	rtt, resp, err := requireOK(a.c.doRequest(r))
   232  	if err != nil {
   233  		return nil, nil, err
   234  	}
   235  	defer resp.Body.Close()
   236  
   237  	qm := &QueryMeta{}
   238  	parseQueryMeta(resp, qm)
   239  	qm.RequestTime = rtt
   240  
   241  	var entries []*ACLEntry
   242  	if err := decodeBody(resp, &entries); err != nil {
   243  		return nil, nil, err
   244  	}
   245  	return entries, qm, nil
   246  }
   247  
   248  // Replication returns the status of the ACL replication process in the datacenter
   249  func (a *ACL) Replication(q *QueryOptions) (*ACLReplicationStatus, *QueryMeta, error) {
   250  	r := a.c.newRequest("GET", "/v1/acl/replication")
   251  	r.setQueryOptions(q)
   252  	rtt, resp, err := requireOK(a.c.doRequest(r))
   253  	if err != nil {
   254  		return nil, nil, err
   255  	}
   256  	defer resp.Body.Close()
   257  
   258  	qm := &QueryMeta{}
   259  	parseQueryMeta(resp, qm)
   260  	qm.RequestTime = rtt
   261  
   262  	var entries *ACLReplicationStatus
   263  	if err := decodeBody(resp, &entries); err != nil {
   264  		return nil, nil, err
   265  	}
   266  	return entries, qm, nil
   267  }
   268  
   269  // TokenCreate creates a new ACL token. It requires that the AccessorID and SecretID fields
   270  // of the ACLToken structure to be empty as these will be filled in by Consul.
   271  func (a *ACL) TokenCreate(token *ACLToken, q *WriteOptions) (*ACLToken, *WriteMeta, error) {
   272  	if token.AccessorID != "" {
   273  		return nil, nil, fmt.Errorf("Cannot specify an AccessorID in Token Creation")
   274  	}
   275  
   276  	if token.SecretID != "" {
   277  		return nil, nil, fmt.Errorf("Cannot specify a SecretID in Token Creation")
   278  	}
   279  
   280  	r := a.c.newRequest("PUT", "/v1/acl/token")
   281  	r.setWriteOptions(q)
   282  	r.obj = token
   283  	rtt, resp, err := requireOK(a.c.doRequest(r))
   284  	if err != nil {
   285  		return nil, nil, err
   286  	}
   287  	defer resp.Body.Close()
   288  
   289  	wm := &WriteMeta{RequestTime: rtt}
   290  	var out ACLToken
   291  	if err := decodeBody(resp, &out); err != nil {
   292  		return nil, nil, err
   293  	}
   294  
   295  	return &out, wm, nil
   296  }
   297  
   298  // TokenUpdate updates a token in place without modifying its AccessorID or SecretID. A valid
   299  // AccessorID must be set in the ACLToken structure passed to this function but the SecretID may
   300  // be omitted and will be filled in by Consul with its existing value.
   301  func (a *ACL) TokenUpdate(token *ACLToken, q *WriteOptions) (*ACLToken, *WriteMeta, error) {
   302  	if token.AccessorID == "" {
   303  		return nil, nil, fmt.Errorf("Must specify an AccessorID for Token Updating")
   304  	}
   305  	r := a.c.newRequest("PUT", "/v1/acl/token/"+token.AccessorID)
   306  	r.setWriteOptions(q)
   307  	r.obj = token
   308  	rtt, resp, err := requireOK(a.c.doRequest(r))
   309  	if err != nil {
   310  		return nil, nil, err
   311  	}
   312  	defer resp.Body.Close()
   313  
   314  	wm := &WriteMeta{RequestTime: rtt}
   315  	var out ACLToken
   316  	if err := decodeBody(resp, &out); err != nil {
   317  		return nil, nil, err
   318  	}
   319  
   320  	return &out, wm, nil
   321  }
   322  
   323  // TokenClone will create a new token with the same policies and locality as the original
   324  // token but will have its own auto-generated AccessorID and SecretID as well having the
   325  // description passed to this function. The tokenID parameter must be a valid Accessor ID
   326  // of an existing token.
   327  func (a *ACL) TokenClone(tokenID string, description string, q *WriteOptions) (*ACLToken, *WriteMeta, error) {
   328  	if tokenID == "" {
   329  		return nil, nil, fmt.Errorf("Must specify a tokenID for Token Cloning")
   330  	}
   331  
   332  	r := a.c.newRequest("PUT", "/v1/acl/token/"+tokenID+"/clone")
   333  	r.setWriteOptions(q)
   334  	r.obj = struct{ Description string }{description}
   335  	rtt, resp, err := requireOK(a.c.doRequest(r))
   336  	if err != nil {
   337  		return nil, nil, err
   338  	}
   339  	defer resp.Body.Close()
   340  
   341  	wm := &WriteMeta{RequestTime: rtt}
   342  	var out ACLToken
   343  	if err := decodeBody(resp, &out); err != nil {
   344  		return nil, nil, err
   345  	}
   346  
   347  	return &out, wm, nil
   348  }
   349  
   350  // TokenDelete removes a single ACL token. The tokenID parameter must be a valid
   351  // Accessor ID of an existing token.
   352  func (a *ACL) TokenDelete(tokenID string, q *WriteOptions) (*WriteMeta, error) {
   353  	r := a.c.newRequest("DELETE", "/v1/acl/token/"+tokenID)
   354  	r.setWriteOptions(q)
   355  	rtt, resp, err := requireOK(a.c.doRequest(r))
   356  	if err != nil {
   357  		return nil, err
   358  	}
   359  	resp.Body.Close()
   360  
   361  	wm := &WriteMeta{RequestTime: rtt}
   362  	return wm, nil
   363  }
   364  
   365  // TokenRead retrieves the full token details. The tokenID parameter must be a valid
   366  // Accessor ID of an existing token.
   367  func (a *ACL) TokenRead(tokenID string, q *QueryOptions) (*ACLToken, *QueryMeta, error) {
   368  	r := a.c.newRequest("GET", "/v1/acl/token/"+tokenID)
   369  	r.setQueryOptions(q)
   370  	rtt, resp, err := requireOK(a.c.doRequest(r))
   371  	if err != nil {
   372  		return nil, nil, err
   373  	}
   374  	defer resp.Body.Close()
   375  
   376  	qm := &QueryMeta{}
   377  	parseQueryMeta(resp, qm)
   378  	qm.RequestTime = rtt
   379  
   380  	var out ACLToken
   381  	if err := decodeBody(resp, &out); err != nil {
   382  		return nil, nil, err
   383  	}
   384  
   385  	return &out, qm, nil
   386  }
   387  
   388  // TokenReadSelf retrieves the full token details of the token currently
   389  // assigned to the API Client. In this manner its possible to read a token
   390  // by its Secret ID.
   391  func (a *ACL) TokenReadSelf(q *QueryOptions) (*ACLToken, *QueryMeta, error) {
   392  	r := a.c.newRequest("GET", "/v1/acl/token/self")
   393  	r.setQueryOptions(q)
   394  	rtt, resp, err := requireOK(a.c.doRequest(r))
   395  	if err != nil {
   396  		return nil, nil, err
   397  	}
   398  	defer resp.Body.Close()
   399  
   400  	qm := &QueryMeta{}
   401  	parseQueryMeta(resp, qm)
   402  	qm.RequestTime = rtt
   403  
   404  	var out ACLToken
   405  	if err := decodeBody(resp, &out); err != nil {
   406  		return nil, nil, err
   407  	}
   408  
   409  	return &out, qm, nil
   410  }
   411  
   412  // TokenList lists all tokens. The listing does not contain any SecretIDs as those
   413  // may only be retrieved by a call to TokenRead.
   414  func (a *ACL) TokenList(q *QueryOptions) ([]*ACLTokenListEntry, *QueryMeta, error) {
   415  	r := a.c.newRequest("GET", "/v1/acl/tokens")
   416  	r.setQueryOptions(q)
   417  	rtt, resp, err := requireOK(a.c.doRequest(r))
   418  	if err != nil {
   419  		return nil, nil, err
   420  	}
   421  	defer resp.Body.Close()
   422  
   423  	qm := &QueryMeta{}
   424  	parseQueryMeta(resp, qm)
   425  	qm.RequestTime = rtt
   426  
   427  	var entries []*ACLTokenListEntry
   428  	if err := decodeBody(resp, &entries); err != nil {
   429  		return nil, nil, err
   430  	}
   431  	return entries, qm, nil
   432  }
   433  
   434  // PolicyCreate will create a new policy. It is not allowed for the policy parameters
   435  // ID field to be set as this will be generated by Consul while processing the request.
   436  func (a *ACL) PolicyCreate(policy *ACLPolicy, q *WriteOptions) (*ACLPolicy, *WriteMeta, error) {
   437  	if policy.ID != "" {
   438  		return nil, nil, fmt.Errorf("Cannot specify an ID in Policy Creation")
   439  	}
   440  
   441  	r := a.c.newRequest("PUT", "/v1/acl/policy")
   442  	r.setWriteOptions(q)
   443  	r.obj = policy
   444  	rtt, resp, err := requireOK(a.c.doRequest(r))
   445  	if err != nil {
   446  		return nil, nil, err
   447  	}
   448  	defer resp.Body.Close()
   449  
   450  	wm := &WriteMeta{RequestTime: rtt}
   451  	var out ACLPolicy
   452  	if err := decodeBody(resp, &out); err != nil {
   453  		return nil, nil, err
   454  	}
   455  
   456  	return &out, wm, nil
   457  }
   458  
   459  // PolicyUpdate updates a policy. The ID field of the policy parameter must be set to an
   460  // existing policy ID
   461  func (a *ACL) PolicyUpdate(policy *ACLPolicy, q *WriteOptions) (*ACLPolicy, *WriteMeta, error) {
   462  	if policy.ID == "" {
   463  		return nil, nil, fmt.Errorf("Must specify an ID in Policy Creation")
   464  	}
   465  
   466  	r := a.c.newRequest("PUT", "/v1/acl/policy/"+policy.ID)
   467  	r.setWriteOptions(q)
   468  	r.obj = policy
   469  	rtt, resp, err := requireOK(a.c.doRequest(r))
   470  	if err != nil {
   471  		return nil, nil, err
   472  	}
   473  	defer resp.Body.Close()
   474  
   475  	wm := &WriteMeta{RequestTime: rtt}
   476  	var out ACLPolicy
   477  	if err := decodeBody(resp, &out); err != nil {
   478  		return nil, nil, err
   479  	}
   480  
   481  	return &out, wm, nil
   482  }
   483  
   484  // PolicyDelete deletes a policy given its ID.
   485  func (a *ACL) PolicyDelete(policyID string, q *WriteOptions) (*WriteMeta, error) {
   486  	r := a.c.newRequest("DELETE", "/v1/acl/policy/"+policyID)
   487  	r.setWriteOptions(q)
   488  	rtt, resp, err := requireOK(a.c.doRequest(r))
   489  	if err != nil {
   490  		return nil, err
   491  	}
   492  	resp.Body.Close()
   493  
   494  	wm := &WriteMeta{RequestTime: rtt}
   495  	return wm, nil
   496  }
   497  
   498  // PolicyRead retrieves the policy details including the rule set.
   499  func (a *ACL) PolicyRead(policyID string, q *QueryOptions) (*ACLPolicy, *QueryMeta, error) {
   500  	r := a.c.newRequest("GET", "/v1/acl/policy/"+policyID)
   501  	r.setQueryOptions(q)
   502  	rtt, resp, err := requireOK(a.c.doRequest(r))
   503  	if err != nil {
   504  		return nil, nil, err
   505  	}
   506  	defer resp.Body.Close()
   507  
   508  	qm := &QueryMeta{}
   509  	parseQueryMeta(resp, qm)
   510  	qm.RequestTime = rtt
   511  
   512  	var out ACLPolicy
   513  	if err := decodeBody(resp, &out); err != nil {
   514  		return nil, nil, err
   515  	}
   516  
   517  	return &out, qm, nil
   518  }
   519  
   520  // PolicyList retrieves a listing of all policies. The listing does not include the
   521  // rules for any policy as those should be retrieved by subsequent calls to PolicyRead.
   522  func (a *ACL) PolicyList(q *QueryOptions) ([]*ACLPolicyListEntry, *QueryMeta, error) {
   523  	r := a.c.newRequest("GET", "/v1/acl/policies")
   524  	r.setQueryOptions(q)
   525  	rtt, resp, err := requireOK(a.c.doRequest(r))
   526  	if err != nil {
   527  		return nil, nil, err
   528  	}
   529  	defer resp.Body.Close()
   530  
   531  	qm := &QueryMeta{}
   532  	parseQueryMeta(resp, qm)
   533  	qm.RequestTime = rtt
   534  
   535  	var entries []*ACLPolicyListEntry
   536  	if err := decodeBody(resp, &entries); err != nil {
   537  		return nil, nil, err
   538  	}
   539  	return entries, qm, nil
   540  }
   541  
   542  // RulesTranslate translates the legacy rule syntax into the current syntax.
   543  //
   544  // Deprecated: Support for the legacy syntax translation will be removed
   545  // when legacy ACL support is removed.
   546  func (a *ACL) RulesTranslate(rules io.Reader) (string, error) {
   547  	r := a.c.newRequest("POST", "/v1/acl/rules/translate")
   548  	r.body = rules
   549  	rtt, resp, err := requireOK(a.c.doRequest(r))
   550  	if err != nil {
   551  		return "", err
   552  	}
   553  	defer resp.Body.Close()
   554  	qm := &QueryMeta{}
   555  	parseQueryMeta(resp, qm)
   556  	qm.RequestTime = rtt
   557  
   558  	ruleBytes, err := ioutil.ReadAll(resp.Body)
   559  	if err != nil {
   560  		return "", fmt.Errorf("Failed to read translated rule body: %v", err)
   561  	}
   562  
   563  	return string(ruleBytes), nil
   564  }
   565  
   566  // RulesTranslateToken translates the rules associated with the legacy syntax
   567  // into the current syntax and returns the results.
   568  //
   569  // Deprecated: Support for the legacy syntax translation will be removed
   570  // when legacy ACL support is removed.
   571  func (a *ACL) RulesTranslateToken(tokenID string) (string, error) {
   572  	r := a.c.newRequest("GET", "/v1/acl/rules/translate/"+tokenID)
   573  	rtt, resp, err := requireOK(a.c.doRequest(r))
   574  	if err != nil {
   575  		return "", err
   576  	}
   577  	defer resp.Body.Close()
   578  	qm := &QueryMeta{}
   579  	parseQueryMeta(resp, qm)
   580  	qm.RequestTime = rtt
   581  
   582  	ruleBytes, err := ioutil.ReadAll(resp.Body)
   583  	if err != nil {
   584  		return "", fmt.Errorf("Failed to read translated rule body: %v", err)
   585  	}
   586  
   587  	return string(ruleBytes), nil
   588  }