mirror of https://github.com/status-im/consul.git
acl: add MaxTokenTTL field to auth methods (#7779)
When set to a non zero value it will limit the ExpirationTime of all tokens created via the auth method.
This commit is contained in:
parent
08b335d8d6
commit
22eb016153
|
@ -2111,6 +2111,16 @@ func (a *ACL) AuthMethodSet(args *structs.ACLAuthMethodSetRequest, reply *struct
|
||||||
return fmt.Errorf("Invalid Auth Method: Type should be one of: %v", authmethod.Types())
|
return fmt.Errorf("Invalid Auth Method: Type should be one of: %v", authmethod.Types())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if method.MaxTokenTTL != 0 {
|
||||||
|
if method.MaxTokenTTL > a.srv.config.ACLTokenMaxExpirationTTL {
|
||||||
|
return fmt.Errorf("MaxTokenTTL %s cannot be more than %s",
|
||||||
|
method.MaxTokenTTL, a.srv.config.ACLTokenMaxExpirationTTL)
|
||||||
|
} else if method.MaxTokenTTL < a.srv.config.ACLTokenMinExpirationTTL {
|
||||||
|
return fmt.Errorf("MaxTokenTTL %s cannot be less than %s",
|
||||||
|
method.MaxTokenTTL, a.srv.config.ACLTokenMinExpirationTTL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Instantiate a validator but do not cache it yet. This will validate the
|
// Instantiate a validator but do not cache it yet. This will validate the
|
||||||
// configuration.
|
// configuration.
|
||||||
if _, err := authmethod.NewValidator(a.srv.logger, method); err != nil {
|
if _, err := authmethod.NewValidator(a.srv.logger, method); err != nil {
|
||||||
|
@ -2323,6 +2333,7 @@ func (a *ACL) Login(args *structs.ACLLoginRequest, reply *structs.ACLToken) erro
|
||||||
AuthMethod: auth.AuthMethod,
|
AuthMethod: auth.AuthMethod,
|
||||||
ServiceIdentities: serviceIdentities,
|
ServiceIdentities: serviceIdentities,
|
||||||
Roles: roleLinks,
|
Roles: roleLinks,
|
||||||
|
ExpirationTTL: method.MaxTokenTTL,
|
||||||
EnterpriseMeta: *targetMeta,
|
EnterpriseMeta: *targetMeta,
|
||||||
},
|
},
|
||||||
WriteRequest: args.WriteRequest,
|
WriteRequest: args.WriteRequest,
|
||||||
|
|
|
@ -3468,6 +3468,89 @@ func TestACLEndpoint_AuthMethodSet(t *testing.T) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
t.Run("Create with MaxTokenTTL", func(t *testing.T) {
|
||||||
|
reqMethod := newAuthMethod("test")
|
||||||
|
reqMethod.MaxTokenTTL = 5 * time.Minute
|
||||||
|
|
||||||
|
req := structs.ACLAuthMethodSetRequest{
|
||||||
|
Datacenter: "dc1",
|
||||||
|
AuthMethod: reqMethod,
|
||||||
|
WriteRequest: structs.WriteRequest{Token: "root"},
|
||||||
|
}
|
||||||
|
resp := structs.ACLAuthMethod{}
|
||||||
|
|
||||||
|
err := acl.AuthMethodSet(&req, &resp)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Get the method directly to validate that it exists
|
||||||
|
methodResp, err := retrieveTestAuthMethod(codec, "root", "dc1", resp.Name)
|
||||||
|
require.NoError(t, err)
|
||||||
|
method := methodResp.AuthMethod
|
||||||
|
|
||||||
|
require.Equal(t, method.Name, "test")
|
||||||
|
require.Equal(t, method.Description, "test")
|
||||||
|
require.Equal(t, method.Type, "testing")
|
||||||
|
require.Equal(t, method.MaxTokenTTL, 5*time.Minute)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Update - change MaxTokenTTL", func(t *testing.T) {
|
||||||
|
reqMethod := newAuthMethod("test")
|
||||||
|
reqMethod.DisplayName = "updated display name 2"
|
||||||
|
reqMethod.Description = "test modified 2"
|
||||||
|
reqMethod.MaxTokenTTL = 8 * time.Minute
|
||||||
|
|
||||||
|
req := structs.ACLAuthMethodSetRequest{
|
||||||
|
Datacenter: "dc1",
|
||||||
|
AuthMethod: reqMethod,
|
||||||
|
WriteRequest: structs.WriteRequest{Token: "root"},
|
||||||
|
}
|
||||||
|
resp := structs.ACLAuthMethod{}
|
||||||
|
|
||||||
|
err := acl.AuthMethodSet(&req, &resp)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Get the method directly to validate that it exists
|
||||||
|
methodResp, err := retrieveTestAuthMethod(codec, "root", "dc1", resp.Name)
|
||||||
|
require.NoError(t, err)
|
||||||
|
method := methodResp.AuthMethod
|
||||||
|
|
||||||
|
require.Equal(t, method.Name, "test")
|
||||||
|
require.Equal(t, method.DisplayName, "updated display name 2")
|
||||||
|
require.Equal(t, method.Description, "test modified 2")
|
||||||
|
require.Equal(t, method.Type, "testing")
|
||||||
|
require.Equal(t, method.MaxTokenTTL, 8*time.Minute)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Create with MaxTokenTTL too small", func(t *testing.T) {
|
||||||
|
reqMethod := newAuthMethod("test")
|
||||||
|
reqMethod.MaxTokenTTL = 1 * time.Millisecond
|
||||||
|
|
||||||
|
req := structs.ACLAuthMethodSetRequest{
|
||||||
|
Datacenter: "dc1",
|
||||||
|
AuthMethod: reqMethod,
|
||||||
|
WriteRequest: structs.WriteRequest{Token: "root"},
|
||||||
|
}
|
||||||
|
resp := structs.ACLAuthMethod{}
|
||||||
|
|
||||||
|
err := acl.AuthMethodSet(&req, &resp)
|
||||||
|
testutil.RequireErrorContains(t, err, "MaxTokenTTL 1ms cannot be less than")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Create with MaxTokenTTL too big", func(t *testing.T) {
|
||||||
|
reqMethod := newAuthMethod("test")
|
||||||
|
reqMethod.MaxTokenTTL = 25 * time.Hour
|
||||||
|
|
||||||
|
req := structs.ACLAuthMethodSetRequest{
|
||||||
|
Datacenter: "dc1",
|
||||||
|
AuthMethod: reqMethod,
|
||||||
|
WriteRequest: structs.WriteRequest{Token: "root"},
|
||||||
|
}
|
||||||
|
resp := structs.ACLAuthMethod{}
|
||||||
|
|
||||||
|
err := acl.AuthMethodSet(&req, &resp)
|
||||||
|
testutil.RequireErrorContains(t, err, "MaxTokenTTL 25h0m0s cannot be more than")
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestACLEndpoint_AuthMethodDelete(t *testing.T) {
|
func TestACLEndpoint_AuthMethodDelete(t *testing.T) {
|
||||||
|
@ -4942,6 +5025,81 @@ func TestACLEndpoint_Login(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestACLEndpoint_Login_with_MaxTokenTTL(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
dir1, s1 := testServerWithConfig(t, func(c *Config) {
|
||||||
|
c.ACLDatacenter = "dc1"
|
||||||
|
c.ACLsEnabled = true
|
||||||
|
c.ACLMasterToken = "root"
|
||||||
|
})
|
||||||
|
defer os.RemoveAll(dir1)
|
||||||
|
defer s1.Shutdown()
|
||||||
|
codec := rpcClient(t, s1)
|
||||||
|
defer codec.Close()
|
||||||
|
|
||||||
|
testrpc.WaitForLeader(t, s1.RPC, "dc1")
|
||||||
|
|
||||||
|
acl := ACL{srv: s1}
|
||||||
|
|
||||||
|
testSessionID := testauth.StartSession()
|
||||||
|
defer testauth.ResetSession(testSessionID)
|
||||||
|
|
||||||
|
testauth.InstallSessionToken(
|
||||||
|
testSessionID,
|
||||||
|
"fake-web", // no rules
|
||||||
|
"default", "web", "abc123",
|
||||||
|
)
|
||||||
|
|
||||||
|
method, err := upsertTestCustomizedAuthMethod(codec, "root", "dc1", func(method *structs.ACLAuthMethod) {
|
||||||
|
method.MaxTokenTTL = 5 * time.Minute
|
||||||
|
method.Config = map[string]interface{}{
|
||||||
|
"SessionID": testSessionID,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = upsertTestBindingRule(
|
||||||
|
codec, "root", "dc1", method.Name,
|
||||||
|
"",
|
||||||
|
structs.BindingRuleBindTypeService,
|
||||||
|
"web",
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Create a token.
|
||||||
|
req := structs.ACLLoginRequest{
|
||||||
|
Auth: &structs.ACLLoginParams{
|
||||||
|
AuthMethod: method.Name,
|
||||||
|
BearerToken: "fake-web",
|
||||||
|
Meta: map[string]string{"pod": "pod1"},
|
||||||
|
},
|
||||||
|
Datacenter: "dc1",
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := structs.ACLToken{}
|
||||||
|
require.NoError(t, acl.Login(&req, &resp))
|
||||||
|
|
||||||
|
got := &resp
|
||||||
|
got.CreateIndex = 0
|
||||||
|
got.ModifyIndex = 0
|
||||||
|
got.AccessorID = ""
|
||||||
|
got.SecretID = ""
|
||||||
|
got.Hash = nil
|
||||||
|
|
||||||
|
expect := &structs.ACLToken{
|
||||||
|
AuthMethod: method.Name,
|
||||||
|
Description: `token created via login: {"pod":"pod1"}`,
|
||||||
|
Local: true,
|
||||||
|
CreateTime: got.CreateTime,
|
||||||
|
ExpirationTime: timePointer(got.CreateTime.Add(method.MaxTokenTTL)),
|
||||||
|
ServiceIdentities: []*structs.ACLServiceIdentity{
|
||||||
|
{ServiceName: "web"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
require.Equal(t, got, expect)
|
||||||
|
}
|
||||||
|
|
||||||
func TestACLEndpoint_Login_k8s(t *testing.T) {
|
func TestACLEndpoint_Login_k8s(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ package structs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"hash"
|
"hash"
|
||||||
|
@ -1048,6 +1049,9 @@ type ACLAuthMethod struct {
|
||||||
// Description is just an optional bunch of explanatory text.
|
// Description is just an optional bunch of explanatory text.
|
||||||
Description string `json:",omitempty"`
|
Description string `json:",omitempty"`
|
||||||
|
|
||||||
|
// MaxTokenTTL this is the maximum life of a token created by this method.
|
||||||
|
MaxTokenTTL time.Duration `json:",omitempty"`
|
||||||
|
|
||||||
// Configuration is arbitrary configuration for the auth method. This
|
// Configuration is arbitrary configuration for the auth method. This
|
||||||
// should only contain primitive values and containers (such as lists and
|
// should only contain primitive values and containers (such as lists and
|
||||||
// maps).
|
// maps).
|
||||||
|
@ -1060,6 +1064,47 @@ type ACLAuthMethod struct {
|
||||||
RaftIndex `hash:"ignore"`
|
RaftIndex `hash:"ignore"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *ACLAuthMethod) MarshalJSON() ([]byte, error) {
|
||||||
|
type Alias ACLAuthMethod
|
||||||
|
exported := &struct {
|
||||||
|
MaxTokenTTL string `json:",omitempty"`
|
||||||
|
*Alias
|
||||||
|
}{
|
||||||
|
MaxTokenTTL: m.MaxTokenTTL.String(),
|
||||||
|
Alias: (*Alias)(m),
|
||||||
|
}
|
||||||
|
if m.MaxTokenTTL == 0 {
|
||||||
|
exported.MaxTokenTTL = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return json.Marshal(exported)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ACLAuthMethod) UnmarshalJSON(data []byte) (err error) {
|
||||||
|
type Alias ACLAuthMethod
|
||||||
|
aux := &struct {
|
||||||
|
MaxTokenTTL interface{}
|
||||||
|
*Alias
|
||||||
|
}{
|
||||||
|
Alias: (*Alias)(m),
|
||||||
|
}
|
||||||
|
if err = lib.UnmarshalJSON(data, &aux); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if aux.MaxTokenTTL != nil {
|
||||||
|
switch v := aux.MaxTokenTTL.(type) {
|
||||||
|
case string:
|
||||||
|
if m.MaxTokenTTL, err = time.ParseDuration(v); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case float64:
|
||||||
|
m.MaxTokenTTL = time.Duration(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
type ACLReplicationType string
|
type ACLReplicationType string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
43
api/acl.go
43
api/acl.go
|
@ -1,6 +1,7 @@
|
||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
@ -182,8 +183,9 @@ type ACLBindingRule struct {
|
||||||
type ACLAuthMethod struct {
|
type ACLAuthMethod struct {
|
||||||
Name string
|
Name string
|
||||||
Type string
|
Type string
|
||||||
DisplayName string `json:",omitempty"`
|
DisplayName string `json:",omitempty"`
|
||||||
Description string `json:",omitempty"`
|
Description string `json:",omitempty"`
|
||||||
|
MaxTokenTTL time.Duration `json:",omitempty"`
|
||||||
|
|
||||||
// Configuration is arbitrary configuration for the auth method. This
|
// Configuration is arbitrary configuration for the auth method. This
|
||||||
// should only contain primitive values and containers (such as lists and
|
// should only contain primitive values and containers (such as lists and
|
||||||
|
@ -198,6 +200,43 @@ type ACLAuthMethod struct {
|
||||||
Namespace string `json:",omitempty"`
|
Namespace string `json:",omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *ACLAuthMethod) MarshalJSON() ([]byte, error) {
|
||||||
|
type Alias ACLAuthMethod
|
||||||
|
exported := &struct {
|
||||||
|
MaxTokenTTL string `json:",omitempty"`
|
||||||
|
*Alias
|
||||||
|
}{
|
||||||
|
MaxTokenTTL: m.MaxTokenTTL.String(),
|
||||||
|
Alias: (*Alias)(m),
|
||||||
|
}
|
||||||
|
if m.MaxTokenTTL == 0 {
|
||||||
|
exported.MaxTokenTTL = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return json.Marshal(exported)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ACLAuthMethod) UnmarshalJSON(data []byte) error {
|
||||||
|
type Alias ACLAuthMethod
|
||||||
|
aux := &struct {
|
||||||
|
MaxTokenTTL string
|
||||||
|
*Alias
|
||||||
|
}{
|
||||||
|
Alias: (*Alias)(m),
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(data, &aux); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
if aux.MaxTokenTTL != "" {
|
||||||
|
if m.MaxTokenTTL, err = time.ParseDuration(aux.MaxTokenTTL); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
type ACLAuthMethodListEntry struct {
|
type ACLAuthMethodListEntry struct {
|
||||||
Name string
|
Name string
|
||||||
Type string
|
Type string
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/hashicorp/consul/api"
|
"github.com/hashicorp/consul/api"
|
||||||
"github.com/hashicorp/consul/command/acl/authmethod"
|
"github.com/hashicorp/consul/command/acl/authmethod"
|
||||||
|
@ -30,11 +31,12 @@ type cmd struct {
|
||||||
name string
|
name string
|
||||||
displayName string
|
displayName string
|
||||||
description string
|
description string
|
||||||
|
maxTokenTTL time.Duration
|
||||||
|
config string
|
||||||
|
|
||||||
k8sHost string
|
k8sHost string
|
||||||
k8sCACert string
|
k8sCACert string
|
||||||
k8sServiceAccountJWT string
|
k8sServiceAccountJWT string
|
||||||
config string
|
|
||||||
|
|
||||||
showMeta bool
|
showMeta bool
|
||||||
format string
|
format string
|
||||||
|
@ -77,6 +79,12 @@ func (c *cmd) init() {
|
||||||
"",
|
"",
|
||||||
"A description of the auth method.",
|
"A description of the auth method.",
|
||||||
)
|
)
|
||||||
|
c.flags.DurationVar(
|
||||||
|
&c.maxTokenTTL,
|
||||||
|
"max-token-ttl",
|
||||||
|
0,
|
||||||
|
"Duration of time all tokens created by this auth method should be valid for",
|
||||||
|
)
|
||||||
|
|
||||||
c.flags.StringVar(
|
c.flags.StringVar(
|
||||||
&c.k8sHost,
|
&c.k8sHost,
|
||||||
|
@ -150,6 +158,9 @@ func (c *cmd) Run(args []string) int {
|
||||||
DisplayName: c.displayName,
|
DisplayName: c.displayName,
|
||||||
Description: c.description,
|
Description: c.description,
|
||||||
}
|
}
|
||||||
|
if c.maxTokenTTL > 0 {
|
||||||
|
newAuthMethod.MaxTokenTTL = c.maxTokenTTL
|
||||||
|
}
|
||||||
|
|
||||||
if c.config != "" {
|
if c.config != "" {
|
||||||
if c.k8sHost != "" || c.k8sCACert != "" || c.k8sServiceAccountJWT != "" {
|
if c.k8sHost != "" || c.k8sCACert != "" || c.k8sServiceAccountJWT != "" {
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/hashicorp/consul/agent"
|
"github.com/hashicorp/consul/agent"
|
||||||
"github.com/hashicorp/consul/agent/connect"
|
"github.com/hashicorp/consul/agent/connect"
|
||||||
|
@ -121,6 +122,35 @@ func TestAuthMethodCreateCommand(t *testing.T) {
|
||||||
}
|
}
|
||||||
require.Equal(t, expect, got)
|
require.Equal(t, expect, got)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("create testing with max token ttl", func(t *testing.T) {
|
||||||
|
args := []string{
|
||||||
|
"-http-addr=" + a.HTTPAddr(),
|
||||||
|
"-token=root",
|
||||||
|
"-type=testing",
|
||||||
|
"-name=test",
|
||||||
|
"-description=desc",
|
||||||
|
"-display-name=display",
|
||||||
|
"-max-token-ttl=5m",
|
||||||
|
}
|
||||||
|
|
||||||
|
ui := cli.NewMockUi()
|
||||||
|
cmd := New(ui)
|
||||||
|
|
||||||
|
code := cmd.Run(args)
|
||||||
|
require.Equal(t, code, 0, "err: "+ui.ErrorWriter.String())
|
||||||
|
require.Empty(t, ui.ErrorWriter.String())
|
||||||
|
|
||||||
|
got := getTestMethod(t, client, "test")
|
||||||
|
expect := &api.ACLAuthMethod{
|
||||||
|
Name: "test",
|
||||||
|
Type: "testing",
|
||||||
|
DisplayName: "display",
|
||||||
|
Description: "desc",
|
||||||
|
MaxTokenTTL: 5 * time.Minute,
|
||||||
|
}
|
||||||
|
require.Equal(t, expect, got)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAuthMethodCreateCommand_JSON(t *testing.T) {
|
func TestAuthMethodCreateCommand_JSON(t *testing.T) {
|
||||||
|
@ -190,6 +220,53 @@ func TestAuthMethodCreateCommand_JSON(t *testing.T) {
|
||||||
}
|
}
|
||||||
require.Equal(t, expect, got)
|
require.Equal(t, expect, got)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("create testing with max token ttl", func(t *testing.T) {
|
||||||
|
args := []string{
|
||||||
|
"-http-addr=" + a.HTTPAddr(),
|
||||||
|
"-token=root",
|
||||||
|
"-type=testing",
|
||||||
|
"-name=test",
|
||||||
|
"-description=desc",
|
||||||
|
"-display-name=display",
|
||||||
|
"-max-token-ttl=5m",
|
||||||
|
"-format=json",
|
||||||
|
}
|
||||||
|
|
||||||
|
ui := cli.NewMockUi()
|
||||||
|
cmd := New(ui)
|
||||||
|
|
||||||
|
code := cmd.Run(args)
|
||||||
|
out := ui.OutputWriter.String()
|
||||||
|
|
||||||
|
require.Equal(t, code, 0)
|
||||||
|
require.Empty(t, ui.ErrorWriter.String())
|
||||||
|
require.Contains(t, out, "test")
|
||||||
|
|
||||||
|
got := getTestMethod(t, client, "test")
|
||||||
|
expect := &api.ACLAuthMethod{
|
||||||
|
Name: "test",
|
||||||
|
Type: "testing",
|
||||||
|
DisplayName: "display",
|
||||||
|
Description: "desc",
|
||||||
|
MaxTokenTTL: 5 * time.Minute,
|
||||||
|
}
|
||||||
|
require.Equal(t, expect, got)
|
||||||
|
|
||||||
|
var raw map[string]interface{}
|
||||||
|
require.NoError(t, json.Unmarshal([]byte(out), &raw))
|
||||||
|
delete(raw, "CreateIndex")
|
||||||
|
delete(raw, "ModifyIndex")
|
||||||
|
|
||||||
|
require.Equal(t, map[string]interface{}{
|
||||||
|
"Name": "test",
|
||||||
|
"Type": "testing",
|
||||||
|
"DisplayName": "display",
|
||||||
|
"Description": "desc",
|
||||||
|
"MaxTokenTTL": "5m0s",
|
||||||
|
"Config": nil,
|
||||||
|
}, raw)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAuthMethodCreateCommand_k8s(t *testing.T) {
|
func TestAuthMethodCreateCommand_k8s(t *testing.T) {
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/hashicorp/consul/api"
|
"github.com/hashicorp/consul/api"
|
||||||
"github.com/hashicorp/consul/command/acl/authmethod"
|
"github.com/hashicorp/consul/command/acl/authmethod"
|
||||||
|
@ -28,9 +29,11 @@ type cmd struct {
|
||||||
|
|
||||||
name string
|
name string
|
||||||
|
|
||||||
displayName string
|
displayName string
|
||||||
description string
|
description string
|
||||||
config string
|
maxTokenTTL time.Duration
|
||||||
|
config string
|
||||||
|
|
||||||
k8sHost string
|
k8sHost string
|
||||||
k8sCACert string
|
k8sCACert string
|
||||||
k8sServiceAccountJWT string
|
k8sServiceAccountJWT string
|
||||||
|
@ -74,6 +77,13 @@ func (c *cmd) init() {
|
||||||
"A description of the auth method.",
|
"A description of the auth method.",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
c.flags.DurationVar(
|
||||||
|
&c.maxTokenTTL,
|
||||||
|
"max-token-ttl",
|
||||||
|
0,
|
||||||
|
"Duration of time all tokens created by this auth method should be valid for",
|
||||||
|
)
|
||||||
|
|
||||||
c.flags.StringVar(
|
c.flags.StringVar(
|
||||||
&c.config,
|
&c.config,
|
||||||
"config",
|
"config",
|
||||||
|
@ -169,6 +179,10 @@ func (c *cmd) Run(args []string) int {
|
||||||
DisplayName: c.displayName,
|
DisplayName: c.displayName,
|
||||||
Description: c.description,
|
Description: c.description,
|
||||||
}
|
}
|
||||||
|
if c.maxTokenTTL > 0 {
|
||||||
|
method.MaxTokenTTL = c.maxTokenTTL
|
||||||
|
}
|
||||||
|
|
||||||
if c.config != "" {
|
if c.config != "" {
|
||||||
if c.k8sHost != "" || c.k8sCACert != "" || c.k8sServiceAccountJWT != "" {
|
if c.k8sHost != "" || c.k8sCACert != "" || c.k8sServiceAccountJWT != "" {
|
||||||
c.UI.Error(fmt.Sprintf("Cannot use command line arguments with '-config' flag"))
|
c.UI.Error(fmt.Sprintf("Cannot use command line arguments with '-config' flag"))
|
||||||
|
@ -184,6 +198,7 @@ func (c *cmd) Run(args []string) int {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if currentAuthMethod.Type == "kubernetes" {
|
if currentAuthMethod.Type == "kubernetes" {
|
||||||
if c.k8sHost == "" {
|
if c.k8sHost == "" {
|
||||||
c.UI.Error(fmt.Sprintf("Missing required '-kubernetes-host' flag"))
|
c.UI.Error(fmt.Sprintf("Missing required '-kubernetes-host' flag"))
|
||||||
|
@ -211,6 +226,9 @@ func (c *cmd) Run(args []string) int {
|
||||||
if c.displayName != "" {
|
if c.displayName != "" {
|
||||||
method.DisplayName = c.displayName
|
method.DisplayName = c.displayName
|
||||||
}
|
}
|
||||||
|
if c.maxTokenTTL > 0 {
|
||||||
|
method.MaxTokenTTL = c.maxTokenTTL
|
||||||
|
}
|
||||||
if c.config != "" {
|
if c.config != "" {
|
||||||
if c.k8sHost != "" || c.k8sCACert != "" || c.k8sServiceAccountJWT != "" {
|
if c.k8sHost != "" || c.k8sCACert != "" || c.k8sServiceAccountJWT != "" {
|
||||||
c.UI.Error(fmt.Sprintf("Cannot use command line arguments with '-config' flag"))
|
c.UI.Error(fmt.Sprintf("Cannot use command line arguments with '-config' flag"))
|
||||||
|
|
|
@ -51,6 +51,14 @@ The table below shows this endpoint's support for
|
||||||
- `DisplayName` `(string: "")` - An optional name to use instead of the `Name`
|
- `DisplayName` `(string: "")` - An optional name to use instead of the `Name`
|
||||||
field when displaying information about this auth method. Added in Consul 1.8.0.
|
field when displaying information about this auth method. Added in Consul 1.8.0.
|
||||||
|
|
||||||
|
- `MaxTokenTTL` `(duration: 0s)` - This specifies the maximum life of any token
|
||||||
|
created by this auth method. When set it will initialize the
|
||||||
|
[`ExpirationTime`](/api/acl/tokens.html#expirationtime) field on all tokens
|
||||||
|
to a value of `Token.CreateTime + AuthMethod.MaxTokenTTL`. This field is not
|
||||||
|
persisted beyond its initial use. Can be specified in the form of `"60s"` or
|
||||||
|
`"5m"` (i.e., 60 seconds or 5 minutes, respectively). This value must be no
|
||||||
|
smaller than 1 minute and no longer than 24 hours. Added in Consul 1.8.0.
|
||||||
|
|
||||||
- `Config` `(map[string]string: <required>)` - The raw configuration to use for
|
- `Config` `(map[string]string: <required>)` - The raw configuration to use for
|
||||||
the chosen auth method. Contents will vary depending upon the type chosen.
|
the chosen auth method. Contents will vary depending upon the type chosen.
|
||||||
For more information on configuring specific auth method types, see the [auth
|
For more information on configuring specific auth method types, see the [auth
|
||||||
|
@ -191,6 +199,14 @@ The table below shows this endpoint's support for
|
||||||
- `DisplayName` `(string: "")` - An optional name to use instead of the `Name`
|
- `DisplayName` `(string: "")` - An optional name to use instead of the `Name`
|
||||||
field when displaying information about this auth method. Added in Consul 1.8.0.
|
field when displaying information about this auth method. Added in Consul 1.8.0.
|
||||||
|
|
||||||
|
- `MaxTokenTTL` `(duration: 0s)` - This specifies the maximum life of any token
|
||||||
|
created by this auth method. When set it will initialize the
|
||||||
|
[`ExpirationTime`](/api/acl/tokens.html#expirationtime) field on all tokens
|
||||||
|
to a value of `Token.CreateTime + AuthMethod.MaxTokenTTL`. This field is not
|
||||||
|
persisted beyond its initial use. Can be specified in the form of `"60s"` or
|
||||||
|
`"5m"` (i.e., 60 seconds or 5 minutes, respectively). This value must be no
|
||||||
|
smaller than 1 minute and no longer than 24 hours. Added in Consul 1.8.0.
|
||||||
|
|
||||||
- `Config` `(map[string]string: <required>)` - The raw configuration to use for
|
- `Config` `(map[string]string: <required>)` - The raw configuration to use for
|
||||||
the chosen auth method. Contents will vary depending upon the type chosen.
|
the chosen auth method. Contents will vary depending upon the type chosen.
|
||||||
For more information on configuring specific auth method types, see the [auth
|
For more information on configuring specific auth method types, see the [auth
|
||||||
|
|
Loading…
Reference in New Issue