CL: improve acl policy self output for management tokens (#26396)

Improved the acl policy self CLI command to handle both management and client tokens.
Management tokens now display a clear message indicating global access with no individual policies.

Fixes: https://github.com/hashicorp/nomad/issues/26389
This commit is contained in:
Gautam Kumar
2025-08-01 18:32:47 +05:30
committed by GitHub
parent 5dc7e7fe25
commit 6f81222ec8
3 changed files with 63 additions and 48 deletions

View File

@@ -81,6 +81,18 @@ func (c *ACLPolicySelfCommand) Run(args []string) int {
return 1
}
// Read the self token to check its type
token, _, err := client.ACLTokens().Self(nil)
if err != nil {
c.Ui.Error(fmt.Sprintf("Error fetching token: %s", err))
return 1
}
if token.Type == "management" {
c.Ui.Output("This is a management token. No individual policies are assigned.")
return 0
}
policies, _, err := client.ACLPolicies().Self(nil)
if err != nil {
c.Ui.Error(fmt.Sprintf("Error fetching WI policies: %s", err))

View File

@@ -10,70 +10,70 @@ import (
"github.com/hashicorp/nomad/command/agent"
"github.com/hashicorp/nomad/nomad/mock"
"github.com/hashicorp/nomad/nomad/structs"
"github.com/hashicorp/nomad/testutil"
"github.com/shoenig/test/must"
)
func TestACLPolicySelfCommand_ViaEnvVar(t *testing.T) {
const policyName = "nw"
config := func(c *agent.Config) {
c.ACL.Enabled = true
}
srv, _, url := testServer(t, true, config)
defer srv.Shutdown()
t.Cleanup(srv.Shutdown)
state := srv.Agent.Server().State()
// Bootstrap an initial ACL token
token := srv.RootToken
must.NotNil(t, token)
// Create a minimal job
job := mock.MinJob()
// Add a job policy
polArgs := structs.ACLPolicyUpsertRequest{
Policies: []*structs.ACLPolicy{
{
Name: "nw",
Description: "test job can write to nodes",
Rules: `node { policy = "write" }`,
JobACL: &structs.JobACL{
Namespace: job.Namespace,
JobID: job.ID,
createPolicy := func(t *testing.T, srv *agent.TestAgent, token *structs.ACLToken, job *structs.Job) {
args := structs.ACLPolicyUpsertRequest{
Policies: []*structs.ACLPolicy{
{
Name: policyName,
Description: "test job can write to nodes",
Rules: `node { policy = "write" }`,
JobACL: &structs.JobACL{
Namespace: job.Namespace,
JobID: job.ID,
},
},
},
},
WriteRequest: structs.WriteRequest{
Region: job.Region,
AuthToken: token.SecretID,
Namespace: job.Namespace,
},
WriteRequest: structs.WriteRequest{
Region: job.Region,
AuthToken: token.SecretID,
Namespace: job.Namespace,
},
}
reply := structs.GenericResponse{}
must.NoError(t, srv.RPC("ACL.UpsertPolicies", &args, &reply))
}
polReply := structs.GenericResponse{}
must.NoError(t, srv.RPC("ACL.UpsertPolicies", &polArgs, &polReply))
must.NonZero(t, polReply.WriteMeta.Index)
ui := cli.NewMockUi()
cmd := &ACLPolicySelfCommand{Meta: Meta{Ui: ui, flagAddress: url}}
runCommand := func(t *testing.T, url, token string) string {
ui := cli.NewMockUi()
cmd := &ACLPolicySelfCommand{Meta: Meta{Ui: ui, flagAddress: url}}
t.Setenv("NOMAD_TOKEN", token)
must.Zero(t, cmd.Run([]string{"-address=" + url}))
return ui.OutputWriter.String()
}
allocs := testutil.WaitForRunningWithToken(t, srv.RPC, job, token.SecretID)
must.Len(t, 1, allocs)
rootToken := srv.RootToken
alloc, err := state.AllocByID(nil, allocs[0].ID)
must.NoError(t, err)
must.MapContainsKey(t, alloc.SignedIdentities, "t")
wid := alloc.SignedIdentities["t"]
t.Run("SelfPolicy returns correct output for management token", func(t *testing.T) {
createPolicy(t, srv, rootToken, mock.MinJob())
// Fetch info on policies with a JWT
t.Setenv("NOMAD_TOKEN", wid)
code := cmd.Run([]string{"-address=" + url})
must.Zero(t, code)
out := runCommand(t, url, rootToken.SecretID)
must.StrContains(t, out, "This is a management token. No individual policies are assigned.")
})
// Check the output
out := ui.OutputWriter.String()
must.StrContains(t, out, polArgs.Policies[0].Name)
t.Run("SelfPolicy returns correct output for client token", func(t *testing.T) {
job := mock.MinJob()
createPolicy(t, srv, rootToken, job)
// make sure we put the job ACLs in there, too
must.StrContains(t, out, polArgs.Policies[0].JobACL.JobID)
clientToken := mock.ACLToken()
clientToken.Policies = []string{policyName}
must.NoError(t, srv.Agent.Server().State().UpsertACLTokens(
structs.MsgTypeTestSetup, 1, []*structs.ACLToken{clientToken},
))
out := runCommand(t, url, clientToken.SecretID)
must.StrContains(t, out, policyName)
must.StrContains(t, out, job.ID)
})
}