{"record":{"id":"56c16723049bda2b","repo":"hashicorp/nomad","slug":"while-multiple-audiences-is-allowed-it-is-more-se","errorCode":null,"errorMessage":"while multiple audiences is allowed, it is more secure to use 1 audience per identity","messagePattern":"while multiple audiences is allowed, it is more secure to use 1 audience per identity","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"nomad/structs/workload_id.go","lineNumber":510,"sourceCode":"\n\tif wi.Filepath != \"\" && !wi.File {\n\t\tmErr.Errors = append(mErr.Errors, fmt.Errorf(\"file parameter must be true in order to specify filepath\"))\n\t}\n\n\treturn mErr.ErrorOrNil()\n}\n\nfunc (wi *WorkloadIdentity) Warnings() error {\n\tif wi == nil {\n\t\treturn fmt.Errorf(\"must not be nil\")\n\t}\n\n\tvar mErr multierror.Error\n\n\tif n := len(wi.Audience); n == 0 {\n\t\tmErr.Errors = append(mErr.Errors, fmt.Errorf(\"identities without an audience are insecure\"))\n\t} else if n > 1 {\n\t\tmErr.Errors = append(mErr.Errors, fmt.Errorf(\"while multiple audiences is allowed, it is more secure to use 1 audience per identity\"))\n\t}\n\n\tif wi.Name != \"\" && wi.Name != WorkloadIdentityDefaultName {\n\t\tif wi.TTL == 0 {\n\t\t\tmErr.Errors = append(mErr.Errors, fmt.Errorf(\"identities without an expiration are insecure\"))\n\t\t}\n\t}\n\n\t// Warn users about using env vars without restarts\n\tif wi.Env && wi.ChangeMode != WIChangeModeRestart {\n\t\tmErr.Errors = append(mErr.Errors, fmt.Errorf(\"using env=%t without change_mode=%q may result in task not getting updated identity\",\n\t\t\twi.Env, WIChangeModeRestart))\n\t}\n\n\treturn mErr.ErrorOrNil()\n}\n\n// WorkloadIdentityRequest encapsulates the 3 parameters used to generated a","sourceCodeStart":492,"sourceCodeEnd":528,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/structs/workload_id.go#L492-L528","documentation":"WorkloadIdentity.Warnings advises against declaring more than one Audience on a single identity. Multiple audiences widen the token's acceptability and make the aud claim ambiguous; one audience per identity is the secure pattern.","triggerScenarios":"An identity block with audience = [\"a\", \"b\"] (len(wi.Audience) > 1) when Warnings() is called, i.e. two or more entries in wi.Audience.","commonSituations":"Reusing one identity for several consumers (e.g. AWS and Vault) instead of defining separate identities; bulk-copying audience lists into every identity block.","solutions":["Split into one identity per consumer, each with a single audience.","Remove the extra audience entries that are not needed by the task's workload validator.","If multiple audiences are truly required, document the rationale; the warning is advisory and does not block the job."],"exampleFix":"// before\nidentity {\n  name = \"shared\"\n  audience = [\"aws\", \"vault\"]\n}\n// after\nidentity {\n  name = \"aws\"\n  audience = [\"aws\"]\n}\nidentity {\n  name = \"vault\"\n  audience = [\"vault\"]\n}","handlingStrategy":"validation","validationCode":"func validateSingleAudience(wi *structs.WorkloadIdentity) error {\n  if len(wi.Audience) > 1 {\n    return fmt.Errorf(\"identity %q declares %d audiences; use one identity per audience\", wi.Name, len(wi.Audience))\n  }\n  return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Adopt a one-identity-per-consumer convention in job templates.","Review job diffs that add audience entries to existing identities.","Document any intentional multi-audience exceptions in the job spec."],"tags":["nomad","workload-identity","security","jwt"],"backgroundTag":"jwt-audience-mismatch","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}