diff --git a/nomad/job_endpoint.go b/nomad/job_endpoint.go index 1dabf3606..874af7a05 100644 --- a/nomad/job_endpoint.go +++ b/nomad/job_endpoint.go @@ -22,6 +22,16 @@ const ( RegisterEnforceIndexErrPrefix = "Enforcing job modify index" ) +var ( + // vaultConstraint is the implicit constraint added to jobs requesting a + // Vault token + vaultConstraint = &structs.Constraint{ + LTarget: "${attr.vault.version}", + RTarget: ">= 0.6.1", + Operand: structs.ConstraintVersion, + } +) + // Job endpoint is used for job interactions type Job struct { srv *Server @@ -71,8 +81,8 @@ func (j *Job) Register(args *structs.JobRegisterRequest, reply *structs.JobRegis } // Ensure that the job has permissions for the requested Vault tokens - desiredPolicies := structs.VaultPoliciesSet(args.Job.VaultPolicies()) - if len(desiredPolicies) != 0 { + policies := args.Job.VaultPolicies() + if len(policies) != 0 { vconf := j.srv.config.VaultConfig if !vconf.Enabled { return fmt.Errorf("Vault not enabled and Vault policies requested") @@ -97,13 +107,36 @@ func (j *Job) Register(args *structs.JobRegisterRequest, reply *structs.JobRegis // If we are given a root token it can access all policies if !lib.StrContains(allowedPolicies, "root") { - subset, offending := structs.SliceStringIsSubset(allowedPolicies, desiredPolicies) + flatPolicies := structs.VaultPoliciesSet(policies) + subset, offending := structs.SliceStringIsSubset(allowedPolicies, flatPolicies) if !subset { return fmt.Errorf("Passed Vault Token doesn't allow access to the following policies: %s", strings.Join(offending, ", ")) } } } + + // Add implicit constraints that the task groups are run on a Node with + // Vault + for _, tg := range args.Job.TaskGroups { + _, ok := policies[tg.Name] + if !ok { + // Not requesting Vault + continue + } + + found := false + for _, c := range tg.Constraints { + if c.Equal(vaultConstraint) { + found = true + break + } + } + + if !found { + tg.Constraints = append(tg.Constraints, vaultConstraint) + } + } } // Clear the Vault token diff --git a/nomad/job_endpoint_test.go b/nomad/job_endpoint_test.go index 81ab8ea04..d909032cd 100644 --- a/nomad/job_endpoint_test.go +++ b/nomad/job_endpoint_test.go @@ -547,6 +547,16 @@ func TestJobEndpoint_Register_Vault_Policies(t *testing.T) { t.Fatalf("vault token not cleared") } + // Check that an implicit constraint was created + constraints := out.TaskGroups[0].Constraints + if l := len(constraints); l != 1 { + t.Fatalf("Unexpected number of tests: %v", l) + } + + if !constraints[0].Equal(vaultConstraint) { + t.Fatalf("bad constraint; got %#v; want %#v", constraints[0], vaultConstraint) + } + // Create the register request with another job asking for a vault policy but // send the root Vault token job2 := mock.Job() diff --git a/nomad/structs/structs.go b/nomad/structs/structs.go index f5791874a..a0f752bbb 100644 --- a/nomad/structs/structs.go +++ b/nomad/structs/structs.go @@ -2534,6 +2534,13 @@ type Constraint struct { str string // Memoized string } +// Equal checks if two constraints are equal +func (c *Constraint) Equal(o *Constraint) bool { + return c.LTarget == o.LTarget && + c.RTarget == o.RTarget && + c.Operand == o.Operand +} + func (c *Constraint) Copy() *Constraint { if c == nil { return nil