From fdf6120987b9d23fca7fdab5241362982f1f1713 Mon Sep 17 00:00:00 2001 From: Chelsea Holland Komlo Date: Tue, 12 Sep 2017 15:56:55 +0000 Subject: [PATCH 1/3] add acl token as meta flag add API test for job ACL --- api/jobs_test.go | 41 +++++++++++++++++++++++++++++++ command/job_status_test.go | 50 ++++++++++++++++++++++++++++++++++++++ command/meta.go | 12 +++++++++ command/meta_test.go | 1 + nomad/job_endpoint.go | 1 + 5 files changed, 105 insertions(+) diff --git a/api/jobs_test.go b/api/jobs_test.go index 7c91b1402..7bb80a5e3 100644 --- a/api/jobs_test.go +++ b/api/jobs_test.go @@ -8,8 +8,10 @@ import ( "time" "github.com/hashicorp/nomad/helper" + "github.com/hashicorp/nomad/nomad/mock" "github.com/hashicorp/nomad/testutil" "github.com/kr/pretty" + "github.com/stretchr/testify/assert" ) func TestJobs_Register(t *testing.T) { @@ -1295,3 +1297,42 @@ func TestJobs_Sort(t *testing.T) { t.Fatalf("\n\n%#v\n\n%#v", jobs, expect) } } + +func TestJobs_Summary_WithACL(t *testing.T) { + t.Parallel() + assert := assert.New(t) + + c, s, root := makeACLClient(t, nil, nil) + defer s.Stop() + jobs := c.Jobs() + + invalidToken := mock.ACLToken() + + // Registering with an invalid token should fail + c.SetSecretID(invalidToken.SecretID) + job := testJob() + _, _, err := jobs.Register(job, nil) + assert.NotNil(err) + + // Register with token should succeed + c.SetSecretID(root.SecretID) + resp2, wm, err := jobs.Register(job, nil) + assert.Nil(err) + assert.NotNil(resp2) + assert.NotEqual("", resp2.EvalID) + assertWriteMeta(t, wm) + + // Query the job summary with an invalid token should fail + c.SetSecretID(invalidToken.SecretID) + result, _, err := jobs.Summary(*job.ID, nil) + assert.NotNil(err) + + // Query the job summary with a valid token should succeed + c.SetSecretID(root.SecretID) + result, qm, err := jobs.Summary(*job.ID, nil) + assert.Nil(err) + assertQueryMeta(t, qm) + + // Check that the result is what we expect + assert.Equal(*job.ID, result.JobID) +} diff --git a/command/job_status_test.go b/command/job_status_test.go index a25da244e..b0971db22 100644 --- a/command/job_status_test.go +++ b/command/job_status_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/hashicorp/nomad/api" + "github.com/hashicorp/nomad/command/agent" "github.com/hashicorp/nomad/nomad/mock" "github.com/mitchellh/cli" "github.com/posener/complete" @@ -215,6 +216,55 @@ func TestJobStatusCommand_AutocompleteArgs(t *testing.T) { assert.Equal(j.ID, res[0]) } +func TestJobStatusCommand_WithAccessPolicy(t *testing.T) { + assert := assert.New(t) + t.Parallel() + + config := func(c *agent.Config) { + c.ACL.Enabled = true + } + + srv, client, url := testServer(t, true, config) + defer srv.Shutdown() + + // Bootstrap an initial ACL token + token := srv.Token + assert.NotNil(token, "failed to bootstrap ACL token") + + // Register a job + j := testJob("job1_sfx") + + invalidToken := mock.ACLToken() + + ui := new(cli.MockUi) + cmd := &JobStatusCommand{Meta: Meta{Ui: ui, flagAddress: url}} + + // registering a job without a token fails + client.SetSecretID(invalidToken.SecretID) + resp, _, err := client.Jobs().Register(j, nil) + assert.NotNil(err) + + // registering a job with a valid token succeeds + client.SetSecretID(token.SecretID) + resp, _, err = client.Jobs().Register(j, nil) + assert.Nil(err) + code := waitForSuccess(ui, client, fullId, t, resp.EvalID) + assert.Equal(0, code) + + // Request Job List without providing a valid token + code = cmd.Run([]string{"-address=" + url, "-token=" + invalidToken.SecretID, "-short"}) + assert.Equal(1, code) + + // Request Job List with a valid token + code = cmd.Run([]string{"-address=" + url, "-token=" + token.SecretID, "-short"}) + assert.Equal(0, code) + + out := ui.OutputWriter.String() + if !strings.Contains(out, *j.ID) { + t.Fatalf("should contain full identifiers, got %s", out) + } +} + func waitForSuccess(ui cli.Ui, client *api.Client, length int, t *testing.T, evalId string) int { mon := newMonitor(ui, client, length) monErr := mon.monitor(evalId, false) diff --git a/command/meta.go b/command/meta.go index 7a30c8a43..32acf6f24 100644 --- a/command/meta.go +++ b/command/meta.go @@ -47,6 +47,9 @@ type Meta struct { // namespace to send API requests namespace string + // token is used for ACLs to access privilaged information + token string + caCert string caPath string clientCert string @@ -74,6 +77,7 @@ func (m *Meta) FlagSet(n string, fs FlagSetFlags) *flag.FlagSet { f.StringVar(&m.clientKey, "client-key", "", "") f.BoolVar(&m.insecure, "insecure", false, "") f.BoolVar(&m.insecure, "tls-skip-verify", false, "") + f.StringVar(&m.token, "token", "", "") } @@ -110,6 +114,7 @@ func (m *Meta) AutocompleteFlags(fs FlagSetFlags) complete.Flags { "-client-key": complete.PredictFiles("*"), "-insecure": complete.PredictNothing, "-tls-skip-verify": complete.PredictNothing, + "-token": complete.PredictAnything, } } @@ -142,6 +147,10 @@ func (m *Meta) Client() (*api.Client, error) { config.TLSConfig = t } + if m.token != "" { + config.SecretID = m.token + } + return api.NewClient(config) } @@ -198,6 +207,9 @@ func generalOptionsUsage() string { -tls-skip-verify Do not verify TLS certificate. This is highly not recommended. Verification will also be skipped if NOMAD_SKIP_VERIFY is set. + + -token + Provide an ACL token to access privilated information ` return strings.TrimSpace(helpText) } diff --git a/command/meta_test.go b/command/meta_test.go index 301339e46..da20d37aa 100644 --- a/command/meta_test.go +++ b/command/meta_test.go @@ -30,6 +30,7 @@ func TestMeta_FlagSet(t *testing.T) { "client-key", "insecure", "tls-skip-verify", + "token", }, }, } diff --git a/nomad/job_endpoint.go b/nomad/job_endpoint.go index e9d352255..bd6a63810 100644 --- a/nomad/job_endpoint.go +++ b/nomad/job_endpoint.go @@ -281,6 +281,7 @@ func getSignalConstraint(signals []string) *structs.Constraint { // Summary retreives the summary of a job func (j *Job) Summary(args *structs.JobSummaryRequest, reply *structs.JobSummaryResponse) error { + if done, err := j.srv.forward("Job.Summary", args, args, reply); done { return err } From e0594a307a3698c50ad237e6aa9b43fabe9eb543 Mon Sep 17 00:00:00 2001 From: Chelsea Holland Komlo Date: Fri, 15 Sep 2017 03:59:28 +0000 Subject: [PATCH 2/3] fixups from code review --- command/meta.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/command/meta.go b/command/meta.go index 32acf6f24..ee9bbba3d 100644 --- a/command/meta.go +++ b/command/meta.go @@ -210,6 +210,8 @@ func generalOptionsUsage() string { -token Provide an ACL token to access privilated information + The SecretID of an ACL token to use to authenticate API requests with. + Additionally, the NOMAD_TOKEN env var will also be sourced. ` return strings.TrimSpace(helpText) } From e2dc75d8530032417f01fe4341a606c54dbdaa64 Mon Sep 17 00:00:00 2001 From: Chelsea Holland Komlo Date: Fri, 15 Sep 2017 04:30:14 +0000 Subject: [PATCH 3/3] update comment to use from other commands --- command/meta.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/command/meta.go b/command/meta.go index ee9bbba3d..18a77cd32 100644 --- a/command/meta.go +++ b/command/meta.go @@ -209,9 +209,8 @@ func generalOptionsUsage() string { will also be skipped if NOMAD_SKIP_VERIFY is set. -token - Provide an ACL token to access privilated information - The SecretID of an ACL token to use to authenticate API requests with. - Additionally, the NOMAD_TOKEN env var will also be sourced. + The SecretID of an ACL token to use to authenticate API requests with. + Overrides the NOMAD_TOKEN environment variable if set. ` return strings.TrimSpace(helpText) }