From 0217136abd632ba347c5b44fa73f219b530cbc59 Mon Sep 17 00:00:00 2001 From: Kerby Geffrard Date: Fri, 15 May 2026 17:27:53 -0400 Subject: [PATCH] Simpify examples/full and simplify testing against local build --- Makefile | 27 +++- README.md | 21 ++- docs/index.md | 202 +++++++------------------ examples/full/.terraform.lock.hcl | 21 +++ examples/full/Makefile | 28 ++++ examples/full/README.md | 50 ++++++ examples/full/main.tf | 200 +++++++----------------- examples/full/terraform.tfvars.example | 8 +- templates/index.md.tmpl | 2 +- 9 files changed, 246 insertions(+), 313 deletions(-) create mode 100644 examples/full/Makefile create mode 100644 examples/full/README.md diff --git a/Makefile b/Makefile index 4da4a38..1a54944 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,10 @@ VERSION := $(shell cat VERSION) LDFLAGS := -X main.version=$(VERSION) -.PHONY: build lint test docs check-docs clean +TERRAFORMRC := $(HOME)/.terraformrc +DEV_MARKER := \# splitsecure-dev-override + +.PHONY: build lint test docs check-docs clean install-dev uninstall-dev build: go build -ldflags '$(LDFLAGS)' -o terraform-provider-splitsecure . @@ -25,3 +28,25 @@ check-docs: docs clean: rm -f terraform-provider-splitsecure + +install-dev: build + @if [ -f $(TERRAFORMRC) ] && ! grep -q '^$(DEV_MARKER)' $(TERRAFORMRC); then \ + echo "$(TERRAFORMRC) exists and is not managed by this Makefile." >&2; \ + echo "Back it up and re-run 'make install-dev'." >&2; \ + exit 1; \ + fi + @printf '$(DEV_MARKER)\nprovider_installation {\n dev_overrides {\n "splitsecure/splitsecure" = "%s"\n }\n direct {}\n}\n' "$(CURDIR)" > $(TERRAFORMRC) + @echo "Dev override installed in $(TERRAFORMRC)." + @echo "All terraform invocations now use $(CURDIR)/terraform-provider-splitsecure." + @echo "Run 'make uninstall-dev' to remove." + +uninstall-dev: + @if [ ! -f $(TERRAFORMRC) ]; then \ + echo "$(TERRAFORMRC) does not exist -- nothing to remove."; \ + elif grep -q '^$(DEV_MARKER)' $(TERRAFORMRC); then \ + rm $(TERRAFORMRC); \ + echo "Removed $(TERRAFORMRC)."; \ + else \ + echo "$(TERRAFORMRC) is not managed by this Makefile -- not touched." >&2; \ + exit 1; \ + fi diff --git a/README.md b/README.md index dabe596..0d6634d 100644 --- a/README.md +++ b/README.md @@ -17,20 +17,19 @@ Generated reference docs live in [`docs/`](./docs); per-resource attribute table ## Installation (dev override) +To test a local build against any plan (including `examples/full`) without +publishing to the registry, use the one-off install target. It builds the +provider and writes `~/.terraformrc` with a `dev_overrides` block pointing +at the local binary; from then on every `terraform` invocation on this +machine uses the local build for `splitsecure/splitsecure`: + ```bash -make build +make install-dev # build + write ~/.terraformrc +make uninstall-dev # remove ~/.terraformrc ``` -Then in `~/.terraformrc`: - -```hcl -provider_installation { - dev_overrides { - "splitsecure/splitsecure" = "/path/to/terraform-provider-splitsecure" - } - direct {} -} -``` +`install-dev` refuses to clobber an existing `~/.terraformrc` it didn't +write (detected via a marker comment); back it up first if you have one. ## Provider Configuration diff --git a/docs/index.md b/docs/index.md index 18f1679..f594420 100644 --- a/docs/index.md +++ b/docs/index.md @@ -39,7 +39,7 @@ provider "splitsecure" { ## Full Example -End-to-end wiring: two teams (Engineering and Technical Support) each with a SAML2 IdP, mirrored as `aws_iam_saml_provider` on the AWS side, with IAM roles and team-scoped service providers federated into a single AWS account. Lives at [`examples/full/main.tf`](https://github.com/splitsecure/terraform-provider-splitsecure/tree/main/examples/full) in the repo. +End-to-end wiring: a SplitSecure team with a SAML2 IdP, mirrored as `aws_iam_saml_provider` on the AWS side, with admin and readonly IAM roles and a single SP allowing federation into both. Lives at [`examples/full/main.tf`](https://github.com/splitsecure/terraform-provider-splitsecure/tree/main/examples/full) in the repo. ```terraform terraform { @@ -51,10 +51,6 @@ terraform { source = "hashicorp/aws" version = "~> 5.0" } - time = { - source = "hashicorp/time" - version = "~> 0.11" - } } } @@ -62,82 +58,47 @@ provider "splitsecure" { org_s2r = var.org_s2r } -provider "aws" { - region = "us-east-1" -} +provider "aws" {} variable "org_s2r" { type = string - description = "Org s2r URI hosting the teams below. Used by the provider to spawn the proposal-scoped managed enclave on every Create / Delete." -} - -variable "engineering_team_s2r" { - type = string - description = "Team s2r URI for the Engineering team. Voters here approve every Engineering Create / Delete proposal." + description = "Org s2r URI hosting the team below. Used by the provider to spawn the proposal-scoped managed enclave on every Create / Delete." } -variable "support_team_s2r" { +variable "team_s2r" { type = string - description = "Team s2r URI for the Technical Support team. Voters here approve every Technical Support Create / Delete proposal." + description = "Team s2r URI that owns the IdP and SP. Voters on this team approve every Create / Delete proposal." } -# Resolve the AWS account the federation lands in. data "aws_caller_identity" "current" {} -# Captured the first time `terraform apply` runs and frozen in state -# from then on. -resource "time_static" "rollout" {} - locals { - account_id = data.aws_caller_identity.current.account_id - rollout_date = formatdate("YYYY-MM-DD", time_static.rollout.rfc3339) -} - -# IdPs are per-team: the threshold-signed cert binds to the team's -# voters, so each team gets its own SAML identity. Engineering and -# Technical Support each mint their own. - -resource "splitsecure_saml2_identity_provider" "engineering" { - team_s2r = var.engineering_team_s2r - - name = "engineering/aws-${local.account_id}" - description = "Engineering SAML IdP for AWS account ${local.account_id}." - - justification = "Stand up the Engineering IdP for federation into AWS account ${local.account_id}." + account_id = data.aws_caller_identity.current.account_id } -resource "splitsecure_saml2_identity_provider" "support" { - team_s2r = var.support_team_s2r +resource "splitsecure_saml2_identity_provider" "main" { + team_s2r = var.team_s2r - name = "support/aws-${local.account_id}" - description = "Technical Support SAML IdP for AWS account ${local.account_id}." + name = "aws-${local.account_id}" + description = "SAML IdP from terraform-provider-splitsecure's example plan." - justification = "Stand up the Technical Support IdP for federation into AWS account ${local.account_id}." + justification = "Creating SAML IdP from terraform-provider-splitsecure's example plan." } -# AWS-side mirrors of each IdP. Distinct ARNs so role trust policies -# can grant access per-team. -resource "aws_iam_saml_provider" "engineering" { - name = "splitsecure-engineering-${local.account_id}" - saml_metadata_document = splitsecure_saml2_identity_provider.engineering.metadata_xml +resource "aws_iam_saml_provider" "main" { + name = "splitsecure-${local.account_id}" + saml_metadata_document = splitsecure_saml2_identity_provider.main.metadata_xml } -resource "aws_iam_saml_provider" "support" { - name = "splitsecure-support-${local.account_id}" - saml_metadata_document = splitsecure_saml2_identity_provider.support.metadata_xml -} - -# Admin role: only Engineering can assume it. Trust policy lists just -# the Engineering SAML provider. resource "aws_iam_role" "admin" { name = "SplitSecureAdmin-${local.account_id}" - description = "Admin role assumed via SplitSecure SAML federation by the Engineering team." + description = "Admin role from terraform-provider-splitsecure's example plan." assume_role_policy = jsonencode({ Version = "2012-10-17" Statement = [{ Effect = "Allow" - Principal = { Federated = aws_iam_saml_provider.engineering.arn } + Principal = { Federated = aws_iam_saml_provider.main.arn } Action = "sts:AssumeRoleWithSAML" Condition = { StringEquals = { "SAML:aud" = "https://signin.aws.amazon.com/saml" } @@ -151,24 +112,16 @@ resource "aws_iam_role_policy_attachment" "admin" { policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess" } -# ReadOnly role: shared between Engineering and Technical -# Support. Trust policy lists both SAML providers; ReadOnlyAccess -# attached so it's safe for either team. resource "aws_iam_role" "readonly" { name = "SplitSecureReadOnly-${local.account_id}" - description = "Read-only readonly role assumed via SplitSecure SAML federation by Engineering or Technical Support." + description = "ReadOnly role from terraform-provider-splitsecure's example plan." assume_role_policy = jsonencode({ Version = "2012-10-17" Statement = [{ - Effect = "Allow" - Principal = { - Federated = [ - aws_iam_saml_provider.engineering.arn, - aws_iam_saml_provider.support.arn, - ] - } - Action = "sts:AssumeRoleWithSAML" + Effect = "Allow" + Principal = { Federated = aws_iam_saml_provider.main.arn } + Action = "sts:AssumeRoleWithSAML" Condition = { StringEquals = { "SAML:aud" = "https://signin.aws.amazon.com/saml" } } @@ -181,120 +134,73 @@ resource "aws_iam_role_policy_attachment" "readonly" { policy_arn = "arn:aws:iam::aws:policy/ReadOnlyAccess" } -# Engineering admin SP. sensitivity = "critical" — voters see the -# highest classification on every proposal here. -resource "splitsecure_saml2_service_provider" "engineering_admin" { - team_s2r = var.engineering_team_s2r - idp_resource_s2r = splitsecure_saml2_identity_provider.engineering.id +resource "splitsecure_saml2_service_provider" "main" { + team_s2r = var.team_s2r + idp_resource_s2r = splitsecure_saml2_identity_provider.main.id - name = "engineering/aws-${local.account_id}-admin" - description = "Engineering admin federation into AWS account ${local.account_id}." + name = "aws-${local.account_id}" + description = "SAML SP from terraform-provider-splitsecure's example plan." notification_policy = "notify_everyone" sensitivity = "critical" entity_id = "urn:amazon:webservices" acs_url = "https://signin.aws.amazon.com/saml" - justification = "Engineering federation to assume ${aws_iam_role.admin.name} in AWS account ${local.account_id}." - - account { - kind = "aws" - aws { - saml_provider_arn = aws_iam_saml_provider.engineering.arn - allowed_role_arns = [aws_iam_role.admin.arn] - } - } -} - -# Engineering readonly SP. sensitivity = "low" mirrors the -# read-only blast radius. -resource "splitsecure_saml2_service_provider" "engineering_readonly" { - team_s2r = var.engineering_team_s2r - idp_resource_s2r = splitsecure_saml2_identity_provider.engineering.id - - name = "engineering/aws-${local.account_id}-readonly" - description = "Engineering read-only federation into AWS account ${local.account_id}." - notification_policy = "notify_everyone" - sensitivity = "low" - entity_id = "urn:amazon:webservices" - acs_url = "https://signin.aws.amazon.com/saml" - - justification = "Engineering federation to assume ${aws_iam_role.readonly.name} (AWS managed ReadOnlyAccess) in AWS account ${local.account_id}." - - account { - kind = "aws" - aws { - saml_provider_arn = aws_iam_saml_provider.engineering.arn - allowed_role_arns = [aws_iam_role.readonly.arn] - } - } -} - -# Technical Support readonly SP. Bound to the Support IdP but -# allowed_role_arns points at the same shared readonly role. -resource "splitsecure_saml2_service_provider" "support_readonly" { - team_s2r = var.support_team_s2r - idp_resource_s2r = splitsecure_saml2_identity_provider.support.id - - name = "support/aws-${local.account_id}-readonly" - description = "Technical Support read-only federation into AWS account ${local.account_id}." - notification_policy = "notify_everyone" - sensitivity = "low" - entity_id = "urn:amazon:webservices" - acs_url = "https://signin.aws.amazon.com/saml" - - justification = "Technical Support federation to assume ${aws_iam_role.readonly.name} (AWS managed ReadOnlyAccess) in AWS account ${local.account_id}." + justification = "Creating SAML SP from terraform-provider-splitsecure's example plan." account { kind = "aws" aws { - saml_provider_arn = aws_iam_saml_provider.support.arn - allowed_role_arns = [aws_iam_role.readonly.arn] + saml_provider_arn = aws_iam_saml_provider.main.arn + allowed_role_arns = [ + aws_iam_role.admin.arn, + aws_iam_role.readonly.arn, + ] } } } output "aws_account_id" { value = local.account_id - description = "AWS account this federation targets." + description = "AWS account ID this federation targets." } -output "rollout_date" { - value = local.rollout_date - description = "Date the federation was first provisioned." +output "idp_s2r" { + value = splitsecure_saml2_identity_provider.main.id + description = "Resource s2r URI of the SplitSecure IdP." } -output "engineering_idp_s2r" { - value = splitsecure_saml2_identity_provider.engineering.id - description = "Resource s2r URI for the Engineering IdP." +output "sp_s2r" { + value = splitsecure_saml2_service_provider.main.id + description = "Resource s2r URI of the SplitSecure SP." } -output "support_idp_s2r" { - value = splitsecure_saml2_identity_provider.support.id - description = "Resource s2r URI for the Technical Support IdP." +output "idp_sso_url_redirect" { + value = splitsecure_saml2_identity_provider.main.sso_url_redirect + description = "SSO URL (HTTP-Redirect binding) assigned by the backend." } -output "engineering_admin_sp_s2r" { - value = splitsecure_saml2_service_provider.engineering_admin.id - description = "Resource s2r URI for the Engineering admin SP (sensitivity = critical)." +output "idp_sso_url_post" { + value = splitsecure_saml2_identity_provider.main.sso_url_post + description = "SSO URL (HTTP-POST binding) assigned by the backend." } -output "engineering_readonly_sp_s2r" { - value = splitsecure_saml2_service_provider.engineering_readonly.id - description = "Resource s2r URI for the Engineering readonly SP (sensitivity = low)." +output "idp_metadata_xml" { + value = splitsecure_saml2_identity_provider.main.metadata_xml + description = "SAML IdP metadata XML rendered from the signing cert, provider_id, and SSO URLs." } -output "support_readonly_sp_s2r" { - value = splitsecure_saml2_service_provider.support_readonly.id - description = "Resource s2r URI for the Technical Support readonly SP (sensitivity = low)." +output "aws_saml_provider_arn" { + value = aws_iam_saml_provider.main.arn + description = "ARN of the AWS-side SAML provider mirror." } -output "admin_role_arn" { +output "aws_admin_role_arn" { value = aws_iam_role.admin.arn - description = "ARN of the admin role (Engineering only)." + description = "ARN of the admin role users assume via SAML." } -output "readonly_role_arn" { +output "aws_readonly_role_arn" { value = aws_iam_role.readonly.arn - description = "ARN of the read-only role (Engineering + Technical Support)." + description = "ARN of the readonly role users assume via SAML." } ``` diff --git a/examples/full/.terraform.lock.hcl b/examples/full/.terraform.lock.hcl index 7bfe11e..36a03a7 100644 --- a/examples/full/.terraform.lock.hcl +++ b/examples/full/.terraform.lock.hcl @@ -43,3 +43,24 @@ provider "registry.terraform.io/hashicorp/time" { "zh:e5b773c0d07e962291be0e9b413c7a22c044b8c7b58c76e8aa91d1659990dfb5", ] } + +provider "registry.terraform.io/splitsecure/splitsecure" { + version = "1.0.1" + hashes = [ + "h1:h5hP7kaMlkyxd1rHeBWc3xeHEaqSq2QMTydhNemwJLE=", + "zh:0da56b350d1ce60f24d5acf5ee65c06180aac53b031ba5e935a347984cf9ec89", + "zh:0e63178f90c60e75de66bbced95205be0352a73b2608547e7f9c29ee496082f4", + "zh:176eadf65e6df653d64477fb7ee7a3ac5c5f7a512c810d7b4df850d390a628d8", + "zh:4277042d6b0830425eee7d520b5cf29da9365cb4c25936181cc11e2a9e463127", + "zh:4e18cffe7e90b516a2e1e5b2377403cb5e4e36e81cfdba0407fd4fd552d305d3", + "zh:53020bbcb86f2a6d8c8978e0e026e9e5aaa839a1d29cf6d3f0a0ada66d7e4149", + "zh:53419234a8b73562b6a1fd4d9b023dc99b83f2dd1e4d06060a0f770fff3c96ca", + "zh:61d48e0bca52c443c7ea24da17cb849cce693d5159c5623561102ec39ba2e2b1", + "zh:6bf17b08a0787d072b2d851c4fba5216d7d4715d34881503e7b05fcd0023234e", + "zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f", + "zh:abbd573050f6566e5505a386e41512e3be69a4a58df0fbdf26dddf3401470c0f", + "zh:ca6e9bd0b87f54b37b9cb7c3de9f3216a333c7e9c9e1094a9ca8095acbeeb05f", + "zh:e169dc4827bf52fcd26b60624926e2d79d2e4ef2de6fa2457752e6abfaf8f90f", + "zh:e4801f1c3bf790689d922e8d556b2c039abac09c38923975b499aa9ee1c1bc01", + ] +} diff --git a/examples/full/Makefile b/examples/full/Makefile new file mode 100644 index 0000000..f422bde --- /dev/null +++ b/examples/full/Makefile @@ -0,0 +1,28 @@ +# End-to-end smoke test against the splitsecure provider on a real backend. +# +# Auth: export SPLITSECURE_BEARER_TOKEN (s2ak_...) before running. + +.PHONY: init plan apply destroy clean help + +help: + @echo "Targets:" + @echo " init terraform init (pulls splitsecure provider from the registry)" + @echo " plan terraform plan" + @echo " apply terraform apply" + @echo " destroy terraform destroy" + @echo " clean remove .terraform, lock file, and tfstate" + +init: + terraform init + +plan: + terraform plan + +apply: + terraform apply + +destroy: + terraform destroy + +clean: + rm -rf .terraform .terraform.lock.hcl terraform.tfstate terraform.tfstate.backup diff --git a/examples/full/README.md b/examples/full/README.md new file mode 100644 index 0000000..170658e --- /dev/null +++ b/examples/full/README.md @@ -0,0 +1,50 @@ +# Full example + +End-to-end smoke test for the `splitsecure/splitsecure` Terraform provider +against a real backend. Stands up a SAML IdP on a SplitSecure team, mirrors +it on AWS as an `aws_iam_saml_provider`, creates admin and readonly IAM +roles, and binds a single SP allowing federation into both roles. + +## Prerequisites + +- Terraform 1.6+ +- AWS credentials in the active shell +- A SplitSecure service-account API key with permission to propose against + `team_s2r` + +## Setup + +AWS credentials must be configured globally in the shell running the +commands (any standard chain works: `AWS_PROFILE`, `AWS_ACCESS_KEY_ID`/ +`AWS_SECRET_ACCESS_KEY`, SSO, IAM role on the instance, etc.). Verify with +`aws sts get-caller-identity` before running terraform. + +```bash +cp terraform.tfvars.example terraform.tfvars +# edit terraform.tfvars: set org_s2r and team_s2r +export SPLITSECURE_BEARER_TOKEN=s2ak_... +``` + +## Usage + +```bash +make init # pull the splitsecure + aws providers from the registry +make plan +make apply # creates 1 IdP + 1 SP (both gated by team voters) +make destroy +make clean # nuke .terraform, lock file, tfstate +``` + +`make apply` produces two proposals on the SplitSecure side (IdP create, SP +create) that must be approved by the team before terraform returns. The SP +sensitivity is `critical` because admin federation is in scope. + +## What gets created + +| Resource | Name pattern | +|---------------------------------------|-----------------------------------------------------| +| `splitsecure_saml2_identity_provider` | `aws-` | +| `aws_iam_saml_provider` | `splitsecure-` | +| `aws_iam_role` (admin) | `SplitSecureAdmin-` + AdministratorAccess | +| `aws_iam_role` (readonly) | `SplitSecureReadOnly-` + ReadOnlyAccess | +| `splitsecure_saml2_service_provider` | `aws-` (allows both roles) | diff --git a/examples/full/main.tf b/examples/full/main.tf index f398bab..2c1087b 100644 --- a/examples/full/main.tf +++ b/examples/full/main.tf @@ -7,10 +7,6 @@ terraform { source = "hashicorp/aws" version = "~> 5.0" } - time = { - source = "hashicorp/time" - version = "~> 0.11" - } } } @@ -18,82 +14,47 @@ provider "splitsecure" { org_s2r = var.org_s2r } -provider "aws" { - region = "us-east-1" -} +provider "aws" {} variable "org_s2r" { type = string - description = "Org s2r URI hosting the teams below. Used by the provider to spawn the proposal-scoped managed enclave on every Create / Delete." -} - -variable "engineering_team_s2r" { - type = string - description = "Team s2r URI for the Engineering team. Voters here approve every Engineering Create / Delete proposal." + description = "Org s2r URI hosting the team below. Used by the provider to spawn the proposal-scoped managed enclave on every Create / Delete." } -variable "support_team_s2r" { +variable "team_s2r" { type = string - description = "Team s2r URI for the Technical Support team. Voters here approve every Technical Support Create / Delete proposal." + description = "Team s2r URI that owns the IdP and SP. Voters on this team approve every Create / Delete proposal." } -# Resolve the AWS account the federation lands in. data "aws_caller_identity" "current" {} -# Captured the first time `terraform apply` runs and frozen in state -# from then on. -resource "time_static" "rollout" {} - locals { - account_id = data.aws_caller_identity.current.account_id - rollout_date = formatdate("YYYY-MM-DD", time_static.rollout.rfc3339) -} - -# IdPs are per-team: the threshold-signed cert binds to the team's -# voters, so each team gets its own SAML identity. Engineering and -# Technical Support each mint their own. - -resource "splitsecure_saml2_identity_provider" "engineering" { - team_s2r = var.engineering_team_s2r - - name = "engineering/aws-${local.account_id}" - description = "Engineering SAML IdP for AWS account ${local.account_id}." - - justification = "Stand up the Engineering IdP for federation into AWS account ${local.account_id}." + account_id = data.aws_caller_identity.current.account_id } -resource "splitsecure_saml2_identity_provider" "support" { - team_s2r = var.support_team_s2r +resource "splitsecure_saml2_identity_provider" "main" { + team_s2r = var.team_s2r - name = "support/aws-${local.account_id}" - description = "Technical Support SAML IdP for AWS account ${local.account_id}." + name = "aws-${local.account_id}" + description = "SAML IdP from terraform-provider-splitsecure's example plan." - justification = "Stand up the Technical Support IdP for federation into AWS account ${local.account_id}." + justification = "Creating SAML IdP from terraform-provider-splitsecure's example plan." } -# AWS-side mirrors of each IdP. Distinct ARNs so role trust policies -# can grant access per-team. -resource "aws_iam_saml_provider" "engineering" { - name = "splitsecure-engineering-${local.account_id}" - saml_metadata_document = splitsecure_saml2_identity_provider.engineering.metadata_xml +resource "aws_iam_saml_provider" "main" { + name = "splitsecure-${local.account_id}" + saml_metadata_document = splitsecure_saml2_identity_provider.main.metadata_xml } -resource "aws_iam_saml_provider" "support" { - name = "splitsecure-support-${local.account_id}" - saml_metadata_document = splitsecure_saml2_identity_provider.support.metadata_xml -} - -# Admin role: only Engineering can assume it. Trust policy lists just -# the Engineering SAML provider. resource "aws_iam_role" "admin" { name = "SplitSecureAdmin-${local.account_id}" - description = "Admin role assumed via SplitSecure SAML federation by the Engineering team." + description = "Admin role from terraform-provider-splitsecure's example plan." assume_role_policy = jsonencode({ Version = "2012-10-17" Statement = [{ Effect = "Allow" - Principal = { Federated = aws_iam_saml_provider.engineering.arn } + Principal = { Federated = aws_iam_saml_provider.main.arn } Action = "sts:AssumeRoleWithSAML" Condition = { StringEquals = { "SAML:aud" = "https://signin.aws.amazon.com/saml" } @@ -107,24 +68,16 @@ resource "aws_iam_role_policy_attachment" "admin" { policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess" } -# ReadOnly role: shared between Engineering and Technical -# Support. Trust policy lists both SAML providers; ReadOnlyAccess -# attached so it's safe for either team. resource "aws_iam_role" "readonly" { name = "SplitSecureReadOnly-${local.account_id}" - description = "Read-only readonly role assumed via SplitSecure SAML federation by Engineering or Technical Support." + description = "ReadOnly role from terraform-provider-splitsecure's example plan." assume_role_policy = jsonencode({ Version = "2012-10-17" Statement = [{ - Effect = "Allow" - Principal = { - Federated = [ - aws_iam_saml_provider.engineering.arn, - aws_iam_saml_provider.support.arn, - ] - } - Action = "sts:AssumeRoleWithSAML" + Effect = "Allow" + Principal = { Federated = aws_iam_saml_provider.main.arn } + Action = "sts:AssumeRoleWithSAML" Condition = { StringEquals = { "SAML:aud" = "https://signin.aws.amazon.com/saml" } } @@ -137,119 +90,72 @@ resource "aws_iam_role_policy_attachment" "readonly" { policy_arn = "arn:aws:iam::aws:policy/ReadOnlyAccess" } -# Engineering admin SP. sensitivity = "critical" — voters see the -# highest classification on every proposal here. -resource "splitsecure_saml2_service_provider" "engineering_admin" { - team_s2r = var.engineering_team_s2r - idp_resource_s2r = splitsecure_saml2_identity_provider.engineering.id +resource "splitsecure_saml2_service_provider" "main" { + team_s2r = var.team_s2r + idp_resource_s2r = splitsecure_saml2_identity_provider.main.id - name = "engineering/aws-${local.account_id}-admin" - description = "Engineering admin federation into AWS account ${local.account_id}." + name = "aws-${local.account_id}" + description = "SAML SP from terraform-provider-splitsecure's example plan." notification_policy = "notify_everyone" sensitivity = "critical" entity_id = "urn:amazon:webservices" acs_url = "https://signin.aws.amazon.com/saml" - justification = "Engineering federation to assume ${aws_iam_role.admin.name} in AWS account ${local.account_id}." - - account { - kind = "aws" - aws { - saml_provider_arn = aws_iam_saml_provider.engineering.arn - allowed_role_arns = [aws_iam_role.admin.arn] - } - } -} - -# Engineering readonly SP. sensitivity = "low" mirrors the -# read-only blast radius. -resource "splitsecure_saml2_service_provider" "engineering_readonly" { - team_s2r = var.engineering_team_s2r - idp_resource_s2r = splitsecure_saml2_identity_provider.engineering.id - - name = "engineering/aws-${local.account_id}-readonly" - description = "Engineering read-only federation into AWS account ${local.account_id}." - notification_policy = "notify_everyone" - sensitivity = "low" - entity_id = "urn:amazon:webservices" - acs_url = "https://signin.aws.amazon.com/saml" - - justification = "Engineering federation to assume ${aws_iam_role.readonly.name} (AWS managed ReadOnlyAccess) in AWS account ${local.account_id}." - - account { - kind = "aws" - aws { - saml_provider_arn = aws_iam_saml_provider.engineering.arn - allowed_role_arns = [aws_iam_role.readonly.arn] - } - } -} - -# Technical Support readonly SP. Bound to the Support IdP but -# allowed_role_arns points at the same shared readonly role. -resource "splitsecure_saml2_service_provider" "support_readonly" { - team_s2r = var.support_team_s2r - idp_resource_s2r = splitsecure_saml2_identity_provider.support.id - - name = "support/aws-${local.account_id}-readonly" - description = "Technical Support read-only federation into AWS account ${local.account_id}." - notification_policy = "notify_everyone" - sensitivity = "low" - entity_id = "urn:amazon:webservices" - acs_url = "https://signin.aws.amazon.com/saml" - - justification = "Technical Support federation to assume ${aws_iam_role.readonly.name} (AWS managed ReadOnlyAccess) in AWS account ${local.account_id}." + justification = "Creating SAML SP from terraform-provider-splitsecure's example plan." account { kind = "aws" aws { - saml_provider_arn = aws_iam_saml_provider.support.arn - allowed_role_arns = [aws_iam_role.readonly.arn] + saml_provider_arn = aws_iam_saml_provider.main.arn + allowed_role_arns = [ + aws_iam_role.admin.arn, + aws_iam_role.readonly.arn, + ] } } } output "aws_account_id" { value = local.account_id - description = "AWS account this federation targets." + description = "AWS account ID this federation targets." } -output "rollout_date" { - value = local.rollout_date - description = "Date the federation was first provisioned." +output "idp_s2r" { + value = splitsecure_saml2_identity_provider.main.id + description = "Resource s2r URI of the SplitSecure IdP." } -output "engineering_idp_s2r" { - value = splitsecure_saml2_identity_provider.engineering.id - description = "Resource s2r URI for the Engineering IdP." +output "sp_s2r" { + value = splitsecure_saml2_service_provider.main.id + description = "Resource s2r URI of the SplitSecure SP." } -output "support_idp_s2r" { - value = splitsecure_saml2_identity_provider.support.id - description = "Resource s2r URI for the Technical Support IdP." +output "idp_sso_url_redirect" { + value = splitsecure_saml2_identity_provider.main.sso_url_redirect + description = "SSO URL (HTTP-Redirect binding) assigned by the backend." } -output "engineering_admin_sp_s2r" { - value = splitsecure_saml2_service_provider.engineering_admin.id - description = "Resource s2r URI for the Engineering admin SP (sensitivity = critical)." +output "idp_sso_url_post" { + value = splitsecure_saml2_identity_provider.main.sso_url_post + description = "SSO URL (HTTP-POST binding) assigned by the backend." } -output "engineering_readonly_sp_s2r" { - value = splitsecure_saml2_service_provider.engineering_readonly.id - description = "Resource s2r URI for the Engineering readonly SP (sensitivity = low)." +output "idp_metadata_xml" { + value = splitsecure_saml2_identity_provider.main.metadata_xml + description = "SAML IdP metadata XML rendered from the signing cert, provider_id, and SSO URLs." } -output "support_readonly_sp_s2r" { - value = splitsecure_saml2_service_provider.support_readonly.id - description = "Resource s2r URI for the Technical Support readonly SP (sensitivity = low)." +output "aws_saml_provider_arn" { + value = aws_iam_saml_provider.main.arn + description = "ARN of the AWS-side SAML provider mirror." } -output "admin_role_arn" { +output "aws_admin_role_arn" { value = aws_iam_role.admin.arn - description = "ARN of the admin role (Engineering only)." + description = "ARN of the admin role users assume via SAML." } -output "readonly_role_arn" { +output "aws_readonly_role_arn" { value = aws_iam_role.readonly.arn - description = "ARN of the read-only role (Engineering + Technical Support)." + description = "ARN of the readonly role users assume via SAML." } diff --git a/examples/full/terraform.tfvars.example b/examples/full/terraform.tfvars.example index 0253657..39d1dee 100644 --- a/examples/full/terraform.tfvars.example +++ b/examples/full/terraform.tfvars.example @@ -1,6 +1,4 @@ -# Copy to terraform.tfvars (gitignored) and fill in your s2r URIs -- -# match the format your existing team / org URIs use. +# Copy to terraform.tfvars (gitignored) and fill in the s2r URIs. -org_s2r = "s2r::org:" -engineering_team_s2r = "s2r::team:" -support_team_s2r = "s2r::team:" +org_s2r = "s2r:us:org:..." +team_s2r = "s2r:us:team:..." diff --git a/templates/index.md.tmpl b/templates/index.md.tmpl index 512a1d5..598f615 100644 --- a/templates/index.md.tmpl +++ b/templates/index.md.tmpl @@ -19,6 +19,6 @@ description: |- ## Full Example -End-to-end wiring: two teams (Engineering and Technical Support) each with a SAML2 IdP, mirrored as `aws_iam_saml_provider` on the AWS side, with IAM roles and team-scoped service providers federated into a single AWS account. Lives at [`examples/full/main.tf`](https://github.com/splitsecure/terraform-provider-splitsecure/tree/main/examples/full) in the repo. +End-to-end wiring: a SplitSecure team with a SAML2 IdP, mirrored as `aws_iam_saml_provider` on the AWS side, with admin and readonly IAM roles and a single SP allowing federation into both. Lives at [`examples/full/main.tf`](https://github.com/splitsecure/terraform-provider-splitsecure/tree/main/examples/full) in the repo. {{tffile "examples/full/main.tf"}}