Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
小 白蛋
Nomad
Commits
44fcdbfa
Unverified
Commit
44fcdbfa
authored
2 years ago
by
James Rasell
Browse files
Options
Download
Email Patches
Plain Diff
WIP
parent
6de242e1
Branches unavailable
No related merge requests found
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
api/acl.go
+29
-13
api/acl.go
api/acl_test.go
+74
-27
api/acl_test.go
command/acl_bootstrap.go
+9
-0
command/acl_bootstrap.go
command/acl_bootstrap_test.go
+2
-0
command/acl_bootstrap_test.go
command/acl_token_create.go
+20
-1
command/acl_token_create.go
command/acl_token_create_test.go
+19
-10
command/acl_token_create_test.go
command/acl_token_list.go
+11
-2
command/acl_token_list.go
with
164 additions
and
53 deletions
+164
-53
api/acl.go
+
29
-
13
View file @
44fcdbfa
...
...
@@ -221,24 +221,40 @@ type ACLPolicy struct {
// ACLToken represents a client token which is used to Authenticate
type
ACLToken
struct
{
AccessorID
string
SecretID
string
Name
string
Type
string
Policies
[]
string
Global
bool
CreateTime
time
.
Time
AccessorID
string
SecretID
string
Name
string
Type
string
Policies
[]
string
Global
bool
CreateTime
time
.
Time
// ExpirationTime represents the point after which a token should be
// considered revoked and is eligible for destruction. The zero value
ExpirationTime
*
time
.
Time
`json:",omitempty"`
// ExpirationTTL is a convenience field for helping set ExpirationTime to a
// value of CreateTime+ExpirationTTL. This can only be set during token
// creation. This is a string version of a time.Duration like "2m".
ExpirationTTL
time
.
Duration
`json:",omitempty"`
CreateIndex
uint64
ModifyIndex
uint64
}
type
ACLTokenListStub
struct
{
AccessorID
string
Name
string
Type
string
Policies
[]
string
Global
bool
CreateTime
time
.
Time
AccessorID
string
Name
string
Type
string
Policies
[]
string
Global
bool
CreateTime
time
.
Time
// ExpirationTime represents the point after which a token should be
// considered revoked and is eligible for destruction. A nil value
// indicates no expiration has been set on the token.
ExpirationTime
*
time
.
Time
`json:"expiration_time,omitempty"`
CreateIndex
uint64
ModifyIndex
uint64
}
...
...
This diff is collapsed.
Click to expand it.
api/acl_test.go
+
74
-
27
View file @
44fcdbfa
...
...
@@ -2,9 +2,11 @@ package api
import
(
"testing"
"time"
"github.com/hashicorp/nomad/api/internal/testutil"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func
TestACLPolicies_ListUpsert
(
t
*
testing
.
T
)
{
...
...
@@ -118,15 +120,10 @@ func TestACLTokens_List(t *testing.T) {
// Expect out bootstrap token
result
,
qm
,
err
:=
at
.
List
(
nil
)
if
err
!=
nil
{
t
.
Fatalf
(
"err: %s"
,
err
)
}
if
qm
.
LastIndex
==
0
{
t
.
Fatalf
(
"bad index: %d"
,
qm
.
LastIndex
)
}
if
n
:=
len
(
result
);
n
!=
1
{
t
.
Fatalf
(
"expected 1 token, got: %d"
,
n
)
}
require
.
NoError
(
t
,
err
)
require
.
NotEqual
(
t
,
0
,
qm
.
LastIndex
)
require
.
Len
(
t
,
result
,
1
)
require
.
Nil
(
t
,
result
[
0
]
.
ExpirationTime
)
}
func
TestACLTokens_CreateUpdate
(
t
*
testing
.
T
)
{
...
...
@@ -156,31 +153,81 @@ func TestACLTokens_CreateUpdate(t *testing.T) {
// Verify the change took hold
assert
.
Equal
(
t
,
out
.
Name
,
out2
.
Name
)
// Try updating the token to include a TTL which is not allowed.
out2
.
ExpirationTTL
=
10
*
time
.
Minute
out3
,
_
,
err
:=
at
.
Update
(
out2
,
nil
)
require
.
Error
(
t
,
err
)
require
.
Nil
(
t
,
out3
)
}
func
TestACLTokens_Info
(
t
*
testing
.
T
)
{
testutil
.
Parallel
(
t
)
c
,
s
,
_
:=
makeACLClient
(
t
,
nil
,
nil
)
defer
s
.
Stop
()
at
:=
c
.
ACLTokens
()
token
:=
&
ACLToken
{
Name
:
"foo"
,
Type
:
"client"
,
Policies
:
[]
string
{
"foo1"
},
testClient
,
testServer
,
_
:=
makeACLClient
(
t
,
nil
,
nil
)
defer
testServer
.
Stop
()
testCases
:=
[]
struct
{
name
string
testFn
func
(
client
*
Client
)
}{
{
name
:
"token without expiry"
,
testFn
:
func
(
client
*
Client
)
{
token
:=
&
ACLToken
{
Name
:
"foo"
,
Type
:
"client"
,
Policies
:
[]
string
{
"foo1"
},
}
// Create the token
out
,
wm
,
err
:=
client
.
ACLTokens
()
.
Create
(
token
,
nil
)
require
.
Nil
(
t
,
err
)
assertWriteMeta
(
t
,
wm
)
require
.
NotNil
(
t
,
out
)
// Query the token
out2
,
qm
,
err
:=
client
.
ACLTokens
()
.
Info
(
out
.
AccessorID
,
nil
)
require
.
Nil
(
t
,
err
)
assertQueryMeta
(
t
,
qm
)
require
.
Equal
(
t
,
out
,
out2
)
},
},
{
name
:
"token with expiry"
,
testFn
:
func
(
client
*
Client
)
{
token
:=
&
ACLToken
{
Name
:
"token-with-expiry"
,
Type
:
"client"
,
Policies
:
[]
string
{
"foo1"
},
ExpirationTTL
:
10
*
time
.
Minute
,
}
// Create the token
out
,
wm
,
err
:=
client
.
ACLTokens
()
.
Create
(
token
,
nil
)
require
.
Nil
(
t
,
err
)
assertWriteMeta
(
t
,
wm
)
require
.
NotNil
(
t
,
out
)
// Query the token and ensure it matches what was returned
// during the creation as well as ensuring the expiration time
// is set.
out2
,
qm
,
err
:=
client
.
ACLTokens
()
.
Info
(
out
.
AccessorID
,
nil
)
require
.
Nil
(
t
,
err
)
assertQueryMeta
(
t
,
qm
)
require
.
Equal
(
t
,
out
,
out2
)
require
.
NotNil
(
t
,
out2
.
ExpirationTime
)
},
},
}
// Create the token
out
,
wm
,
err
:=
at
.
Create
(
token
,
nil
)
assert
.
Nil
(
t
,
err
)
assertWriteMeta
(
t
,
wm
)
assert
.
NotNil
(
t
,
out
)
// Query the token
out2
,
qm
,
err
:=
at
.
Info
(
out
.
AccessorID
,
nil
)
assert
.
Nil
(
t
,
err
)
assertQueryMeta
(
t
,
qm
)
assert
.
Equal
(
t
,
out
,
out2
)
for
_
,
tc
:=
range
testCases
{
t
.
Run
(
tc
.
name
,
func
(
t
*
testing
.
T
)
{
tc
.
testFn
(
testClient
)
})
}
}
func
TestACLTokens_Self
(
t
*
testing
.
T
)
{
...
...
This diff is collapsed.
Click to expand it.
command/acl_bootstrap.go
+
9
-
0
View file @
44fcdbfa
...
...
@@ -5,6 +5,7 @@ import (
"io/ioutil"
"os"
"strings"
"time"
"github.com/hashicorp/nomad/api"
"github.com/posener/complete"
...
...
@@ -163,8 +164,16 @@ func formatKVACLToken(token *api.ACLToken) string {
// Add the generic output
output
=
append
(
output
,
fmt
.
Sprintf
(
"Create Time|%v"
,
token
.
CreateTime
),
fmt
.
Sprintf
(
"Expiry Time |%s"
,
expiryTimeString
(
token
.
ExpirationTime
)),
fmt
.
Sprintf
(
"Create Index|%d"
,
token
.
CreateIndex
),
fmt
.
Sprintf
(
"Modify Index|%d"
,
token
.
ModifyIndex
),
)
return
formatKV
(
output
)
}
func
expiryTimeString
(
t
*
time
.
Time
)
string
{
if
t
==
nil
||
t
.
IsZero
()
{
return
"never"
}
return
t
.
String
()
}
This diff is collapsed.
Click to expand it.
command/acl_bootstrap_test.go
+
2
-
0
View file @
44fcdbfa
...
...
@@ -36,6 +36,7 @@ func TestACLBootstrapCommand(t *testing.T) {
out
:=
ui
.
OutputWriter
.
String
()
assert
.
Contains
(
out
,
"Secret ID"
)
require
.
Contains
(
t
,
out
,
"Expiry Time = never"
)
}
// If a bootstrap token has already been created, attempts to create more should
...
...
@@ -116,6 +117,7 @@ func TestACLBootstrapCommand_WithOperatorFileBootstrapToken(t *testing.T) {
out
:=
ui
.
OutputWriter
.
String
()
assert
.
Contains
(
t
,
out
,
mockToken
.
SecretID
)
require
.
Contains
(
t
,
out
,
"Expiry Time = never"
)
}
// Attempting to bootstrap the server with an invalid operator provided token in a file should
...
...
This diff is collapsed.
Click to expand it.
command/acl_token_create.go
+
20
-
1
View file @
44fcdbfa
...
...
@@ -3,6 +3,7 @@ package command
import
(
"fmt"
"strings"
"time"
"github.com/hashicorp/nomad/api"
"github.com/posener/complete"
...
...
@@ -36,6 +37,11 @@ Create Options:
-policy=""
Specifies a policy to associate with the token. Can be specified multiple times,
but only with client type tokens.
-ttl
Specifies the time-to-live of the created ACL token. This takes the form of
a time duration such as "5m" and "1h". By default, tokens will be created
without a TTL and therefore never expire.
`
return
strings
.
TrimSpace
(
helpText
)
}
...
...
@@ -47,6 +53,7 @@ func (c *ACLTokenCreateCommand) AutocompleteFlags() complete.Flags {
"type"
:
complete
.
PredictAnything
,
"global"
:
complete
.
PredictNothing
,
"policy"
:
complete
.
PredictAnything
,
"ttl"
:
complete
.
PredictAnything
,
})
}
...
...
@@ -61,7 +68,7 @@ func (c *ACLTokenCreateCommand) Synopsis() string {
func
(
c
*
ACLTokenCreateCommand
)
Name
()
string
{
return
"acl token create"
}
func
(
c
*
ACLTokenCreateCommand
)
Run
(
args
[]
string
)
int
{
var
name
,
tokenType
string
var
name
,
tokenType
,
ttl
string
var
global
bool
var
policies
[]
string
flags
:=
c
.
Meta
.
FlagSet
(
c
.
Name
(),
FlagSetClient
)
...
...
@@ -69,6 +76,7 @@ func (c *ACLTokenCreateCommand) Run(args []string) int {
flags
.
StringVar
(
&
name
,
"name"
,
""
,
""
)
flags
.
StringVar
(
&
tokenType
,
"type"
,
"client"
,
""
)
flags
.
BoolVar
(
&
global
,
"global"
,
false
,
""
)
flags
.
StringVar
(
&
ttl
,
"ttl"
,
""
,
""
)
flags
.
Var
((
funcVar
)(
func
(
s
string
)
error
{
policies
=
append
(
policies
,
s
)
return
nil
...
...
@@ -93,6 +101,17 @@ func (c *ACLTokenCreateCommand) Run(args []string) int {
Global
:
global
,
}
// If the user set a TTL flag value, convert this to a time duration and
// add it to our token request object.
if
ttl
!=
""
{
ttlDuration
,
err
:=
time
.
ParseDuration
(
ttl
)
if
err
!=
nil
{
c
.
Ui
.
Error
(
fmt
.
Sprintf
(
"Failed to parse TTL as time duration: %s"
,
err
))
return
1
}
tk
.
ExpirationTTL
=
ttlDuration
}
// Get the HTTP client
client
,
err
:=
c
.
Meta
.
Client
()
if
err
!=
nil
{
...
...
This diff is collapsed.
Click to expand it.
command/acl_token_create_test.go
+
19
-
10
View file @
44fcdbfa
package
command
import
(
"strings"
"testing"
"github.com/hashicorp/nomad/ci"
"github.com/hashicorp/nomad/command/agent"
"github.com/mitchellh/cli"
"github.com/stretchr/testify/
assert
"
"github.com/stretchr/testify/
require
"
)
func
TestACLTokenCreateCommand
(
t
*
testing
.
T
)
{
ci
.
Parallel
(
t
)
assert
:=
assert
.
New
(
t
)
config
:=
func
(
c
*
agent
.
Config
)
{
c
.
ACL
.
Enabled
=
true
}
...
...
@@ -22,22 +21,32 @@ func TestACLTokenCreateCommand(t *testing.T) {
// Bootstrap an initial ACL token
token
:=
srv
.
RootToken
assert
.
NotNil
(
token
,
"failed to bootstrap ACL token"
)
require
.
NotNil
(
t
,
token
,
"failed to bootstrap ACL token"
)
ui
:=
cli
.
NewMockUi
()
cmd
:=
&
ACLTokenCreateCommand
{
Meta
:
Meta
{
Ui
:
ui
,
flagAddress
:
url
}}
// Request to create a new token without providing a valid management token
code
:=
cmd
.
Run
([]
string
{
"-address="
+
url
,
"-token=foo"
,
"-policy=foo"
,
"-type=client"
})
assert
.
Equal
(
1
,
code
)
require
.
Equal
(
t
,
1
,
code
)
// Request to create a new token with a valid management token
// Request to create a new token with a valid management token that does
// not have an expiry set.
code
=
cmd
.
Run
([]
string
{
"-address="
+
url
,
"-token="
+
token
.
SecretID
,
"-policy=foo"
,
"-type=client"
})
assert
.
Equal
(
0
,
code
)
require
.
Equal
(
t
,
0
,
code
)
// Check the output
out
:=
ui
.
OutputWriter
.
String
()
if
!
strings
.
Contains
(
out
,
"[foo]"
)
{
t
.
Fatalf
(
"bad: %v"
,
out
)
}
require
.
Contains
(
t
,
out
,
"[foo]"
)
require
.
Contains
(
t
,
out
,
"Expiry Time = never"
)
ui
.
OutputWriter
.
Reset
()
ui
.
ErrorWriter
.
Reset
()
// Create a new token that has an expiry TTL set and check the response.
code
=
cmd
.
Run
([]
string
{
"-address="
+
url
,
"-token="
+
token
.
SecretID
,
"-type=management"
,
"-ttl=10m"
})
require
.
Equal
(
t
,
0
,
code
)
out
=
ui
.
OutputWriter
.
String
()
require
.
NotContains
(
t
,
out
,
"Expiry Time = never"
)
}
This diff is collapsed.
Click to expand it.
command/acl_token_list.go
+
11
-
2
View file @
44fcdbfa
...
...
@@ -3,6 +3,7 @@ package command
import
(
"fmt"
"strings"
"time"
"github.com/hashicorp/nomad/api"
"github.com/posener/complete"
...
...
@@ -108,9 +109,17 @@ func formatTokens(tokens []*api.ACLTokenListStub) string {
}
output
:=
make
([]
string
,
0
,
len
(
tokens
)
+
1
)
output
=
append
(
output
,
"Name|Type|Global|Accessor ID"
)
output
=
append
(
output
,
"Name|Type|Global|Accessor ID
|Expired
"
)
for
_
,
p
:=
range
tokens
{
output
=
append
(
output
,
fmt
.
Sprintf
(
"%s|%s|%t|%s"
,
p
.
Name
,
p
.
Type
,
p
.
Global
,
p
.
AccessorID
))
expired
:=
false
if
p
.
ExpirationTime
!=
nil
&&
!
p
.
ExpirationTime
.
IsZero
()
{
if
p
.
ExpirationTime
.
Before
(
time
.
Now
()
.
UTC
())
{
expired
=
true
}
}
output
=
append
(
output
,
fmt
.
Sprintf
(
"%s|%s|%t|%s|%v"
,
p
.
Name
,
p
.
Type
,
p
.
Global
,
p
.
AccessorID
,
expired
))
}
return
formatList
(
output
)
...
...
This diff is collapsed.
Click to expand it.
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment
Menu
Projects
Groups
Snippets
Help