parent
a4322afedb
commit
54d47957b5
|
@ -31,10 +31,11 @@ IMPROVEMENTS:
|
|||
* logical: Allow `.` in path-based variables in many more locations [GH-244]
|
||||
* logical: Responses now contain a "warnings" key containing a list of
|
||||
warnings returned from the server. These are conditions that did not require
|
||||
failing an operation, but of which the client should be aware. [GH-676]
|
||||
failing an operation, but of which the client should be aware. [GH-676]
|
||||
* physical/consul: Consul now uses a connection pool to limit the number of
|
||||
outstanding operations, improving behavior when a lot of operations must
|
||||
happen at once [GH-677]
|
||||
* secret/consul: Management tokens can now be created [GH-714]
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package consul
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
|
@ -21,9 +22,10 @@ func TestBackend_basic(t *testing.T) {
|
|||
config, process := testStartConsulServer(t)
|
||||
defer testStopConsulServer(t, process)
|
||||
|
||||
b, _ := Factory(logical.TestBackendConfig())
|
||||
logicaltest.Test(t, logicaltest.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Backend: Backend(),
|
||||
Backend: b,
|
||||
Steps: []logicaltest.TestStep{
|
||||
testAccStepConfig(t, config),
|
||||
testAccStepWritePolicy(t, "test", testPolicy, ""),
|
||||
|
@ -32,13 +34,30 @@ func TestBackend_basic(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestBackend_management(t *testing.T) {
|
||||
config, process := testStartConsulServer(t)
|
||||
defer testStopConsulServer(t, process)
|
||||
|
||||
b, _ := Factory(logical.TestBackendConfig())
|
||||
logicaltest.Test(t, logicaltest.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Backend: b,
|
||||
Steps: []logicaltest.TestStep{
|
||||
testAccStepConfig(t, config),
|
||||
testAccStepWriteManagementPolicy(t, "test", ""),
|
||||
testAccStepReadManagementToken(t, "test", config),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestBackend_crud(t *testing.T) {
|
||||
_, process := testStartConsulServer(t)
|
||||
defer testStopConsulServer(t, process)
|
||||
|
||||
b, _ := Factory(logical.TestBackendConfig())
|
||||
logicaltest.Test(t, logicaltest.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Backend: Backend(),
|
||||
Backend: b,
|
||||
Steps: []logicaltest.TestStep{
|
||||
testAccStepWritePolicy(t, "test", testPolicy, ""),
|
||||
testAccStepReadPolicy(t, "test", testPolicy, DefaultLeaseDuration),
|
||||
|
@ -51,9 +70,10 @@ func TestBackend_role_lease(t *testing.T) {
|
|||
_, process := testStartConsulServer(t)
|
||||
defer testStopConsulServer(t, process)
|
||||
|
||||
b, _ := Factory(logical.TestBackendConfig())
|
||||
logicaltest.Test(t, logicaltest.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Backend: Backend(),
|
||||
Backend: b,
|
||||
Steps: []logicaltest.TestStep{
|
||||
testAccStepWritePolicy(t, "test", testPolicy, "6h"),
|
||||
testAccStepReadPolicy(t, "test", testPolicy, 6*time.Hour),
|
||||
|
@ -85,12 +105,31 @@ func testStartConsulServer(t *testing.T) (map[string]interface{}, *os.Process) {
|
|||
"consul", "agent",
|
||||
"-server",
|
||||
"-bootstrap",
|
||||
"-advertise", "127.0.0.1",
|
||||
"-config-file", tf.Name(),
|
||||
"-data-dir", td)
|
||||
stdout, _ := cmd.StdoutPipe()
|
||||
stderr, _ := cmd.StderrPipe()
|
||||
stdoutScanner := bufio.NewScanner(stdout)
|
||||
stderrScanner := bufio.NewScanner(stderr)
|
||||
stdoutScanFunc := func() {
|
||||
for stdoutScanner.Scan() {
|
||||
t.Logf("Consul stdout: %s\n", stdoutScanner.Text())
|
||||
}
|
||||
}
|
||||
stderrScanFunc := func() {
|
||||
for stderrScanner.Scan() {
|
||||
t.Logf("Consul stderr: %s\n", stderrScanner.Text())
|
||||
}
|
||||
}
|
||||
if os.Getenv("VAULT_VERBOSE_ACC_TESTS") != "" {
|
||||
go stdoutScanFunc()
|
||||
go stderrScanFunc()
|
||||
}
|
||||
|
||||
if err := cmd.Start(); err != nil {
|
||||
t.Fatalf("error starting Consul: %s", err)
|
||||
}
|
||||
|
||||
// Give Consul time to startup
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
|
@ -157,6 +196,43 @@ func testAccStepReadToken(
|
|||
}
|
||||
}
|
||||
|
||||
func testAccStepReadManagementToken(
|
||||
t *testing.T, name string, conf map[string]interface{}) logicaltest.TestStep {
|
||||
return logicaltest.TestStep{
|
||||
Operation: logical.ReadOperation,
|
||||
Path: "creds/" + name,
|
||||
Check: func(resp *logical.Response) error {
|
||||
var d struct {
|
||||
Token string `mapstructure:"token"`
|
||||
}
|
||||
if err := mapstructure.Decode(resp.Data, &d); err != nil {
|
||||
return err
|
||||
}
|
||||
log.Printf("[WARN] Generated token: %s", d.Token)
|
||||
|
||||
// Build a client and verify that the credentials work
|
||||
config := api.DefaultConfig()
|
||||
config.Address = conf["address"].(string)
|
||||
config.Token = d.Token
|
||||
client, err := api.NewClient(config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Printf("[WARN] Verifying that the generated token works...")
|
||||
_, _, err = client.ACL().Create(&api.ACLEntry{
|
||||
Type: "management",
|
||||
Name: "test2",
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func testAccStepWritePolicy(t *testing.T, name string, policy string, lease string) logicaltest.TestStep {
|
||||
return logicaltest.TestStep{
|
||||
Operation: logical.WriteOperation,
|
||||
|
@ -168,6 +244,17 @@ func testAccStepWritePolicy(t *testing.T, name string, policy string, lease stri
|
|||
}
|
||||
}
|
||||
|
||||
func testAccStepWriteManagementPolicy(t *testing.T, name string, lease string) logicaltest.TestStep {
|
||||
return logicaltest.TestStep{
|
||||
Operation: logical.WriteOperation,
|
||||
Path: "roles/" + name,
|
||||
Data: map[string]interface{}{
|
||||
"token_type": "management",
|
||||
"lease": lease,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func testAccStepReadPolicy(t *testing.T, name string, policy string, lease time.Duration) logicaltest.TestStep {
|
||||
return logicaltest.TestStep{
|
||||
Operation: logical.ReadOperation,
|
||||
|
|
|
@ -19,8 +19,18 @@ func pathRoles() *framework.Path {
|
|||
},
|
||||
|
||||
"policy": &framework.FieldSchema{
|
||||
Type: framework.TypeString,
|
||||
Description: "Policy document, base64 encoded.",
|
||||
Type: framework.TypeString,
|
||||
Description: `Policy document, base64 encoded. Required
|
||||
for 'client' tokens.`,
|
||||
},
|
||||
|
||||
"token_type": &framework.FieldSchema{
|
||||
Type: framework.TypeString,
|
||||
Default: "client",
|
||||
Description: `Which type of token to create: 'client'
|
||||
or 'management'. If a 'management' token,
|
||||
the "policy" parameter is not required.
|
||||
Defaults to 'client'.`,
|
||||
},
|
||||
|
||||
"lease": &framework.FieldSchema{
|
||||
|
@ -54,23 +64,49 @@ func pathRolesRead(
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if result.TokenType == "" {
|
||||
result.TokenType = "client"
|
||||
}
|
||||
|
||||
// Generate the response
|
||||
resp := &logical.Response{
|
||||
Data: map[string]interface{}{
|
||||
"policy": base64.StdEncoding.EncodeToString([]byte(result.Policy)),
|
||||
"lease": result.Lease.String(),
|
||||
"lease": result.Lease.String(),
|
||||
"token_type": result.TokenType,
|
||||
},
|
||||
}
|
||||
if result.Policy != "" {
|
||||
resp.Data["policy"] = base64.StdEncoding.EncodeToString([]byte(result.Policy))
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func pathRolesWrite(
|
||||
req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
|
||||
tokenType := d.Get("token_type").(string)
|
||||
|
||||
switch tokenType {
|
||||
case "client":
|
||||
case "management":
|
||||
default:
|
||||
return logical.ErrorResponse(
|
||||
"token_type must be \"client\" or \"management\""), nil
|
||||
}
|
||||
|
||||
name := d.Get("name").(string)
|
||||
policyRaw, err := base64.StdEncoding.DecodeString(d.Get("policy").(string))
|
||||
if err != nil {
|
||||
return logical.ErrorResponse(fmt.Sprintf(
|
||||
"Error decoding policy base64: %s", err)), nil
|
||||
policy := d.Get("policy").(string)
|
||||
var policyRaw []byte
|
||||
var err error
|
||||
if tokenType != "management" {
|
||||
if policy == "" {
|
||||
return logical.ErrorResponse(
|
||||
"policy cannot be empty when not using management tokens"), nil
|
||||
}
|
||||
policyRaw, err = base64.StdEncoding.DecodeString(d.Get("policy").(string))
|
||||
if err != nil {
|
||||
return logical.ErrorResponse(fmt.Sprintf(
|
||||
"Error decoding policy base64: %s", err)), nil
|
||||
}
|
||||
}
|
||||
lease, err := time.ParseDuration(d.Get("lease").(string))
|
||||
if err != nil || lease == time.Duration(0) {
|
||||
|
@ -78,8 +114,9 @@ func pathRolesWrite(
|
|||
}
|
||||
|
||||
entry, err := logical.StorageEntryJSON("policy/"+name, roleConfig{
|
||||
Policy: string(policyRaw),
|
||||
Lease: lease,
|
||||
Policy: string(policyRaw),
|
||||
Lease: lease,
|
||||
TokenType: tokenType,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -102,6 +139,7 @@ func pathRolesDelete(
|
|||
}
|
||||
|
||||
type roleConfig struct {
|
||||
Policy string `json:"policy"`
|
||||
Lease time.Duration `json:"lease"`
|
||||
Policy string `json:"policy"`
|
||||
Lease time.Duration `json:"lease"`
|
||||
TokenType string `json:"token_type"`
|
||||
}
|
||||
|
|
|
@ -42,6 +42,10 @@ func (b *backend) pathTokenRead(
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if result.TokenType == "" {
|
||||
result.TokenType = "client"
|
||||
}
|
||||
|
||||
// Get the consul client
|
||||
c, err := client(req.Storage)
|
||||
if err != nil {
|
||||
|
@ -53,7 +57,7 @@ func (b *backend) pathTokenRead(
|
|||
// Create it
|
||||
token, _, err := c.ACL().Create(&api.ACLEntry{
|
||||
Name: tokenName,
|
||||
Type: "client",
|
||||
Type: result.TokenType,
|
||||
Rules: result.Policy,
|
||||
}, nil)
|
||||
if err != nil {
|
||||
|
|
Loading…
Reference in New Issue