commit 7dceebd028c82b6530f6f3847fe94713b4d3f5ea
parent 5a7162d0b72066fe5381bff055fc2adce1ab12d1
Author: Andreas Gruhler <agruhl@gmx.ch>
Date: Sat, 22 Nov 2025 11:58:18 +0100
doc: Nomad ACL & OIDC setup
Diffstat:
4 files changed, 169 insertions(+), 11 deletions(-)
diff --git a/README.md b/README.md
@@ -84,17 +84,6 @@ certificates in the directory `./tls/nomad/certs`:
./nomad-tls.sh
```
-## Nomad ACL
-TODO
-
-* Describe ACLs for Nomad
-* https://write.in0rdr.ch/nomad-authentication-with-openbao
-
-## Nomad SSO with OpenBao OIDC provider
-TODO
-
-Nomad SSO is configured with OpenBao OpenID Connect provider.
-
## Nomad workload identity configuration
Follow along the tutorial to configure Nomad workload identities with Bao:
* https://developer.hashicorp.com/nomad/tutorials/integrate-vault/vault-acl
@@ -137,6 +126,9 @@ path "kv/+/{{identity.entity.aliases.AUTH_METHOD_ACCESSOR.metadata.nomad_job_id}
$ bao policy write nomad-workloads vault-policy-nomad-workloads.hcl
```
+## Nomad ACL
+Manual setup, see [nomad-acl/README.md](./nomad-acl/README.md)
+
## Authorized Keys
Copy the contents of an openssh pubkey to `authorized_keys` Packer variable.
diff --git a/nomad-acl/README.md b/nomad-acl/README.md
@@ -0,0 +1,110 @@
+## Nomad ACL
+The ACL setup is configured manually (not automated):
+* user of the `userpass` auth method is member of the admin group in OpenBao
+* admin group of OpenBao translates to Nomad admin role on login, see
+ [auth-method-vault.json](./auth-method-vault.json)
+* Nomad binding rule connects auth method and role via claim/selector (see
+ Nomad binding rule below)
+* [admin policy](./policy-admin.hcl) connected to "admin" role in Nomad (see
+ Nomad role config below)
+
+## Nomad SSO with OpenBao OIDC provider
+Nomad SSO is configured with OpenBao OpenID Connect provider.
+* https://developer.hashicorp.com/nomad/tutorials/archive/sso-oidc-vault
+* https://write.in0rdr.ch/nomad-authentication-with-openbao
+
+## Changes required on node leave/join
+Update the list of `redirect_uris` when nodes join/leave.
+* In the OpenBao client (see below)
+* In the [auth-method-vault.json](./auth-method-vault.json) (see below)
+
+### OpenBao OIDC provider and client configuration
+The OpenBao OIDC provider for Nomad restricts usage to the nomad client:
+```bash
+$ bao read identity/oidc/provider/nomad
+Key Value
+--- -----
+allowed_client_ids [$OPENBAO_NOMAD_CLIENT_ID]
+issuer https://vault.in0rdr.ch/v1/identity/oidc/provider/nomad
+scopes_supported [groups]
+```
+
+The OpenBao client for Nomad configures the `redirect_uris`:
+```bash
+$ bao read identity/oidc/client/nomad
+Key Value
+--- -----
+access_token_ttl 1h
+assignments [nomad-oidc-admin]
+client_id ***
+client_secret hvo_secret_***
+client_type confidential
+id_token_ttl 30m
+key default
+redirect_uris [http://localhost:4200/ui/settings/tokens http://localhost:4649/oidc/callback https://intel0.lan:4646/ui/settings/tokens https://pi0.lan:4646/ui/settings/tokens https://pi1.lan:4646/ui/settings/tokens https://pi2.lan:4646/ui/settings/tokens https://pi3.lan:4646/ui/settings/tokens https://pi4.lan:4646/ui/settings/tokens]
+```
+
+To update `redirect_uris`:
+```bash
+$ bao write identity/oidc/client/nomad redirect_uris="space separated"
+```
+
+The "assignment" restricts users of OpenBao admin group to use the Nomad client:
+```bash
+$ bao read identity/oidc/assignment/nomad-oidc-admin
+Key Value
+--- -----
+entity_ids []
+group_ids [$OPENBAO_ADMIN_GROUP_ID]
+```
+
+### Nomad ACL configuration
+The auth method in Nomad is configured with 1h TTL for the `NOMAD_TOKENS`.
+
+```bash
+$ nomad acl auth-method info vault
+Name = vault
+Type = OIDC
+Locality = global
+Max Token TTL = 1h0m0s
+...
+
+OIDC Discovery URL = https://vault.in0rdr.ch/v1/identity/oidc/provider/nomad
+OIDC Enable PKCE = false
+List claim mappings = {groups: roles}
+...
+```
+
+The file [auth-method-vault.json](./auth-method-vault.json) is used to
+configure the Nomad authentication method.
+
+Prepare variables:
+```bash
+ISSUER=$(curl -s https://vault.in0rdr.ch/v1/identity/oidc/provider/nomad/.well-known/openid-configuration | jq -r .issuer)
+CLIENT_ID=$(vault read -field=client_id identity/oidc/client/nomad)
+CLIENT_SECRET=$(vault read -field=client_secret identity/oidc/client/nomad)
+```
+
+Update the JSON file and apply in Nomad (requires management token):
+```bash
+nomad acl auth-method update -config @auth-method-vault.json vault
+```
+
+Nomad ACL binding rule creates connection between JWT claim (signed by OpenBao
+provider) and role:
+```bash
+$ nomad acl binding-rule info $RULE_ID
+...
+Auth Method = vault
+Selector = "admin in list.roles"
+Bind Type = role
+Bind Name = admin
+```
+
+Nomad ACL role assigns policy:
+```bash
+$ nomad acl role info $ROLE_ID
+...
+Name = admin
+Policies = admin
+```
diff --git a/nomad-acl/auth-method-vault.json b/nomad-acl/auth-method-vault.json
@@ -0,0 +1,20 @@
+{
+ "OIDCDiscoveryURL": "https://vault.in0rdr.ch/v1/identity/oidc/provider/nomad",
+ "OIDCClientID": "$CLIENT_ID",
+ "OIDCClientSecret": "$CLIENT_SECRET",
+ "BoundAudiences": ["$CLIENT_ID"],
+ "OIDCScopes": ["groups"],
+ "AllowedRedirectURIs": [
+ "http://localhost:4200/ui/settings/tokens",
+ "http://localhost:4649/oidc/callback",
+ "https://intel0.lan:4646/ui/settings/tokens",
+ "https://pi0.lan:4646/ui/settings/tokens",
+ "https://pi1.lan:4646/ui/settings/tokens",
+ "https://pi2.lan:4646/ui/settings/tokens",
+ "https://pi3.lan:4646/ui/settings/tokens",
+ "https://pi4.lan:4646/ui/settings/tokens"
+ ],
+ "ListClaimMappings": {
+ "groups": "roles"
+ }
+}
diff --git a/nomad-acl/policy-admin.hcl b/nomad-acl/policy-admin.hcl
@@ -0,0 +1,36 @@
+namespace "*" {
+ policy = "write"
+ variables {
+ path "*" {
+ capabilities = ["write", "read", "destroy", "list"]
+ }
+ }
+}
+
+node {
+ policy = "write"
+}
+
+node_pool "*" {
+ policy = "write"
+}
+
+agent {
+ policy = "write"
+}
+
+operator {
+ policy = "write"
+}
+
+quota {
+ policy = "write"
+}
+
+host_volume "*" {
+ policy = "write"
+}
+
+plugin {
+ policy = "read"
+}