client version constraints for implicit identities for WI (#18932)

Clients prior to Nomad 1.7 cannot support the new workload identity-based
authentication to Consul and Vault. Add an implicit Nomad version constraint on
job submission for task groups that use the new workflow.

Includes a constraint test showing same-version prelease handling.
This commit is contained in:
Tim Gross
2023-12-01 13:51:21 -05:00
committed by GitHub
parent 2ba459c73a
commit 0bc2ea8d98
3 changed files with 54 additions and 0 deletions

View File

@@ -19,24 +19,46 @@ func (jobImplicitIdentitiesHook) Name() string {
func (h jobImplicitIdentitiesHook) Mutate(job *structs.Job) (*structs.Job, []error, error) {
for _, tg := range job.TaskGroups {
var hasIdentity bool
for _, s := range tg.Services {
h.handleConsulService(s, tg)
hasIdentity = hasIdentity || s.Identity != nil
}
for _, t := range tg.Tasks {
for _, s := range t.Services {
h.handleConsulService(s, tg)
hasIdentity = hasIdentity || s.Identity != nil
}
if len(t.Templates) > 0 {
h.handleConsulTasks(t, tg)
}
h.handleVault(t)
hasIdentity = hasIdentity || (len(t.Identities) > 0)
}
if hasIdentity {
tg.Constraints = append(tg.Constraints, implicitIdentityClientVersionConstraint())
}
}
return job, nil, nil
}
// implicitIdentityClientVersionConstraint is used when the client needs to
// support a workload identity workflow for Consul or Vault, or multiple
// identities in general.
func implicitIdentityClientVersionConstraint() *structs.Constraint {
// "-a" is used here so that it is "less than" all pre-release versions of
// Nomad 1.7.0 as well
return &structs.Constraint{
LTarget: "${attr.nomad.version}",
RTarget: ">= 1.7.0-a",
Operand: structs.ConstraintSemver,
}
}
// handleConsulService injects a workload identity to the service if:
// 1. The service uses the Consul provider, and
// 2. The server is configured with `consul.service_identity`

View File

@@ -119,6 +119,8 @@ func Test_jobImplicitIdentitiesHook_Mutate_consul_service(t *testing.T) {
},
expectedOutputJob: &structs.Job{
TaskGroups: []*structs.TaskGroup{{
Constraints: []*structs.Constraint{
implicitIdentityClientVersionConstraint()},
Services: []*structs.Service{
{
Provider: "consul",
@@ -195,6 +197,8 @@ func Test_jobImplicitIdentitiesHook_Mutate_consul_service(t *testing.T) {
},
expectedOutputJob: &structs.Job{
TaskGroups: []*structs.TaskGroup{{
Constraints: []*structs.Constraint{
implicitIdentityClientVersionConstraint()},
Services: []*structs.Service{{
Provider: "consul",
PortLabel: "80",
@@ -245,6 +249,8 @@ func Test_jobImplicitIdentitiesHook_Mutate_consul_service(t *testing.T) {
expectedOutputJob: &structs.Job{
TaskGroups: []*structs.TaskGroup{{
Name: "group",
Constraints: []*structs.Constraint{
implicitIdentityClientVersionConstraint()},
Tasks: []*structs.Task{{
Name: "web-task",
Templates: []*structs.Template{{}},
@@ -371,6 +377,8 @@ func Test_jobImplicitIndentitiesHook_Mutate_vault(t *testing.T) {
},
expectedOutputJob: &structs.Job{
TaskGroups: []*structs.TaskGroup{{
Constraints: []*structs.Constraint{
implicitIdentityClientVersionConstraint()},
Tasks: []*structs.Task{{
Identities: []*structs.WorkloadIdentity{{
Name: "vault_default",
@@ -405,6 +413,8 @@ func Test_jobImplicitIndentitiesHook_Mutate_vault(t *testing.T) {
},
expectedOutputJob: &structs.Job{
TaskGroups: []*structs.TaskGroup{{
Constraints: []*structs.Constraint{
implicitIdentityClientVersionConstraint()},
Tasks: []*structs.Task{{
Identities: []*structs.WorkloadIdentity{{
Name: "vault_default",
@@ -444,6 +454,8 @@ func Test_jobImplicitIndentitiesHook_Mutate_vault(t *testing.T) {
},
expectedOutputJob: &structs.Job{
TaskGroups: []*structs.TaskGroup{{
Constraints: []*structs.Constraint{
implicitIdentityClientVersionConstraint()},
Tasks: []*structs.Task{{
Identities: []*structs.WorkloadIdentity{{
Name: "vault_other",

View File

@@ -1315,6 +1315,26 @@ func TestCheckSemverConstraint(t *testing.T) {
lVal: "1.7.0-alpha1", rVal: ">= 1.6.0-beta1",
result: true,
},
{
name: "Prereleases of same version handled according to semver",
lVal: "1.7.0-beta", rVal: ">= 1.7.0",
result: false,
},
{
name: "Prereleases constraints allow GA version according to semver",
lVal: "1.7.0", rVal: ">= 1.7.0-dev",
result: true,
},
{
name: "Prereleases constraints allow beta according to semver",
lVal: "1.7.0-beta.1", rVal: ">= 1.7.0-a",
result: true,
},
{
name: "Prereleases constraints allow RC version according to semver",
lVal: "1.7.0-rc.1", rVal: ">= 1.7.0-dev",
result: true,
},
{
name: "Meta is ignored according to semver",
lVal: "1.3.0-beta1+ent", rVal: "= 1.3.0-beta1",