aws node attester: add org verification support (#825)

* add verify org support for aws node attester

Signed-off-by: pratik-lotia <[email protected]>

* refactor with suggested changes

Signed-off-by: pratik-lotia <[email protected]>

---------

Signed-off-by: pratik-lotia <[email protected]>
This commit is contained in:
Pratik Lotia
2026-05-12 12:25:07 -07:00
committed by GitHub
parent f9a2c443a6
commit 806c6ae59e
4 changed files with 65 additions and 0 deletions
@@ -435,6 +435,12 @@ In order to run Tornjak with simple HTTP Connection only, make sure you don't cr
| `nodeAttestor.tpmDirect.hashes` | A list of TPM hashes that are allowed to connect. | `[]` |
| `nodeAttestor.awsIID.enabled` | Enable the aws_iid node attestor | `false` |
| `nodeAttestor.awsIID.assumeRole` | AWS IAM Role NAME to use for the attestation | `""` |
| `nodeAttestor.awsIID.verifyOrganization` | When enabled, SPIRE verifies the attesting node's AWS account is a member of your AWS Organization ([SPIRE aws_iid server plugin](https://github.com/spiffe/spire/blob/main/doc/plugin_server_nodeattestor_aws_iid.md)). | |
| `nodeAttestor.awsIID.verifyOrganization.enabled` | Enable AWS Organizations membership validation (`verify_organization` in plugin config) | `false` |
| `nodeAttestor.awsIID.verifyOrganization.managementAccountId` | AWS Organizations management/root account ID (12 digits); SPIRE assumes `arn:aws:iam::<managementAccountId>:role/<assumeOrgRole>` for listing org accounts. | `""` |
| `nodeAttestor.awsIID.verifyOrganization.assumeOrgRole` | IAM role **name** in the management account; must allow `organizations:ListAccounts` and trust the IAM identity used by the SPIRE server. | `""` |
| `nodeAttestor.awsIID.verifyOrganization.managementAccountRegion` | Optional region SPIRE uses for org validation/cache keying (defaults in SPIRE if unset). | `""` |
| `nodeAttestor.awsIID.verifyOrganization.orgAccountMapTTL` | Optional cache TTL for the org account map (SPIRE expects a duration ≥ 1m when set; e.g. `3m`, `5m`). Defaults to 3 minutes. | `3m` |
| `nodeAttestor.gcpIIT.enabled` | Enable the gcp_iit node attestor | `false` |
| `nodeAttestor.gcpIIT.projectIDAllowList` | List of ProjectIDs from which nodes can be attested | `[]` |
| `nodeAttestor.gcpIIT.useInstanceMetadata` | If true, instance metadata is fetched from the Google Compute Engine API and used to augment the node selectors produced by the plugin | `false` |
@@ -159,6 +159,14 @@ plugins:
{{- end }}
disable_migration: {{ .Values.dataStore.sql.disableMigration }}
{{- with .Values.nodeAttestor.awsIID.verifyOrganization }}
{{- if and (eq ($.Values.nodeAttestor.awsIID.enabled | toString) "true") (eq (.enabled | toString) "true") }}
{{- if or (eq .managementAccountId "") (eq .assumeOrgRole "") }}
{{- fail "nodeAttestor.awsIID.verifyOrganization requires managementAccountId and assumeOrgRole when enabled=true" }}
{{- end }}
{{- end }}
{{- end }}
{{- if or .Values.nodeAttestor.k8sPSAT.enabled .Values.nodeAttestor.externalK8sPSAT.enabled .Values.nodeAttestor.joinToken.enabled .Values.nodeAttestor.httpChallenge.enabled .Values.nodeAttestor.tpmDirect.enabled .Values.nodeAttestor.awsIID.enabled .Values.nodeAttestor.gcpIIT.enabled }}
NodeAttestor:
{{- $clusters := default .Values.kubeConfigs .Values.nodeAttestor.externalK8sPSAT.clusters }}
@@ -246,6 +254,19 @@ plugins:
{{- if ne .assumeRole "" }}
assume_role: {{ .assumeRole | quote }}
{{- end }}
{{- with .verifyOrganization }}
{{- if eq (.enabled | toString) "true" }}
verify_organization:
management_account_id: {{ .managementAccountId | quote }}
assume_org_role: {{ .assumeOrgRole | quote }}
{{- if ne .managementAccountRegion "" }}
management_account_region: {{ .managementAccountRegion | quote }}
{{- end }}
{{- if ne .orgAccountMapTTL "" }}
org_account_map_ttl: {{ .orgAccountMapTTL | quote }}
{{- end }}
{{- end }}
{{- end }}
{{- end }}
{{- end }}
{{- with .Values.nodeAttestor.gcpIIT }}
@@ -1074,6 +1074,18 @@ nodeAttestor:
enabled: false
## @param nodeAttestor.awsIID.assumeRole AWS IAM Role NAME to use for the attestation
assumeRole: ""
## @extra nodeAttestor.awsIID.verifyOrganization When enabled, SPIRE verifies the attesting node's AWS account is a member of your AWS Organization ([SPIRE aws_iid server plugin](https://github.com/spiffe/spire/blob/main/doc/plugin_server_nodeattestor_aws_iid.md)).
verifyOrganization:
## @param nodeAttestor.awsIID.verifyOrganization.enabled Enable AWS Organizations membership validation (`verify_organization` in plugin config)
enabled: false
## @param nodeAttestor.awsIID.verifyOrganization.managementAccountId AWS Organizations management/root account ID (12 digits); SPIRE assumes `arn:aws:iam::<managementAccountId>:role/<assumeOrgRole>` for listing org accounts.
managementAccountId: ""
## @param nodeAttestor.awsIID.verifyOrganization.assumeOrgRole IAM role **name** in the management account; must allow `organizations:ListAccounts` and trust the IAM identity used by the SPIRE server.
assumeOrgRole: ""
## @param nodeAttestor.awsIID.verifyOrganization.managementAccountRegion Optional region SPIRE uses for org validation/cache keying (defaults in SPIRE if unset).
managementAccountRegion: ""
## @param nodeAttestor.awsIID.verifyOrganization.orgAccountMapTTL Optional cache TTL for the org account map (SPIRE expects a duration ≥ 1m when set; e.g. `3m`, `5m`). Defaults to 3 minutes.
orgAccountMapTTL: "3m"
gcpIIT:
## @param nodeAttestor.gcpIIT.enabled Enable the gcp_iit node attestor
enabled: false
+26
View File
@@ -150,6 +150,32 @@ spire-server:
Expect(notes).Should(ContainSubstring("Installed"))
})
})
Describe("spire-server.nodeAttestor.awsIID.verifyOrganization", func() {
It("emits verify_organization in server config JSON", func() {
objs, err := ValueStringRender(chart, `
spire-server:
nodeAttestor:
k8sPSAT:
enabled: false
awsIID:
enabled: true
verifyOrganization:
enabled: true
managementAccountId: "111122223333"
assumeOrgRole: "spire-server-org-validator"
managementAccountRegion: "us-east-1"
orgAccountMapTTL: "5m"
`)
Expect(err).Should(Succeed())
notes := objs["spire/charts/spire-server/templates/configmap.yaml"]
Expect(notes).Should(ContainSubstring(`verify_organization`))
Expect(notes).Should(ContainSubstring(`management_account_id`))
Expect(notes).Should(ContainSubstring(`111122223333`))
Expect(notes).Should(ContainSubstring(`spire-server-org-validator`))
Expect(notes).Should(ContainSubstring(`us-east-1`))
Expect(notes).Should(ContainSubstring(`5m`))
})
})
Describe("spire-server.credentialComposer.uniqueID", func() {
It("spire server uniqueid credential composer", func() {
objs, err := ValueStringRender(chart, `