From 91d8489cfec3d20a318f272e1270f95c16e7a2f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Gonz=C3=A1lez=20Di=20Antonio?= Date: Fri, 3 Apr 2026 11:43:48 +0200 Subject: [PATCH 1/7] feat: update dependencies --- go.mod | 12 ++++++------ go.sum | 24 ++++++++++++------------ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/go.mod b/go.mod index 74e1d02..dbcb39e 100644 --- a/go.mod +++ b/go.mod @@ -5,8 +5,8 @@ go 1.26.1 require ( github.com/aws/aws-lambda-go v1.54.0 github.com/aws/aws-sdk-go-v2 v1.41.5 - github.com/aws/aws-sdk-go-v2/config v1.32.13 - github.com/aws/aws-sdk-go-v2/credentials v1.19.13 + github.com/aws/aws-sdk-go-v2/config v1.32.14 + github.com/aws/aws-sdk-go-v2/credentials v1.19.14 github.com/aws/aws-sdk-go-v2/service/s3 v1.98.0 github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.41.5 github.com/google/go-cmp v0.7.0 @@ -17,7 +17,7 @@ require ( go.uber.org/mock v0.6.0 golang.org/x/oauth2 v0.36.0 golang.org/x/sync v0.20.0 - google.golang.org/api v0.273.1 + google.golang.org/api v0.274.0 gopkg.in/yaml.v3 v3.0.1 ) @@ -36,10 +36,10 @@ require ( github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.21 // indirect github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.21 // indirect github.com/aws/aws-sdk-go-v2/service/signin v1.0.9 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.30.14 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.18 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.30.15 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.19 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.41.10 // indirect - github.com/aws/smithy-go v1.24.2 // indirect + github.com/aws/smithy-go v1.24.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/felixge/httpsnoop v1.0.4 // indirect diff --git a/go.sum b/go.sum index fd26493..69d2b2a 100644 --- a/go.sum +++ b/go.sum @@ -10,10 +10,10 @@ github.com/aws/aws-sdk-go-v2 v1.41.5 h1:dj5kopbwUsVUVFgO4Fi5BIT3t4WyqIDjGKCangnV github.com/aws/aws-sdk-go-v2 v1.41.5/go.mod h1:mwsPRE8ceUUpiTgF7QmQIJ7lgsKUPQOUl3o72QBrE1o= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.8 h1:eBMB84YGghSocM7PsjmmPffTa+1FBUeNvGvFou6V/4o= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.8/go.mod h1:lyw7GFp3qENLh7kwzf7iMzAxDn+NzjXEAGjKS2UOKqI= -github.com/aws/aws-sdk-go-v2/config v1.32.13 h1:5KgbxMaS2coSWRrx9TX/QtWbqzgQkOdEa3sZPhBhCSg= -github.com/aws/aws-sdk-go-v2/config v1.32.13/go.mod h1:8zz7wedqtCbw5e9Mi2doEwDyEgHcEE9YOJp6a8jdSMY= -github.com/aws/aws-sdk-go-v2/credentials v1.19.13 h1:mA59E3fokBvyEGHKFdnpNNrvaR351cqiHgRg+JzOSRI= -github.com/aws/aws-sdk-go-v2/credentials v1.19.13/go.mod h1:yoTXOQKea18nrM69wGF9jBdG4WocSZA1h38A+t/MAsk= +github.com/aws/aws-sdk-go-v2/config v1.32.14 h1:opVIRo/ZbbI8OIqSOKmpFaY7IwfFUOCCXBsUpJOwDdI= +github.com/aws/aws-sdk-go-v2/config v1.32.14/go.mod h1:U4/V0uKxh0Tl5sxmCBZ3AecYny4UNlVmObYjKuuaiOo= +github.com/aws/aws-sdk-go-v2/credentials v1.19.14 h1:n+UcGWAIZHkXzYt87uMFBv/l8THYELoX6gVcUvgl6fI= +github.com/aws/aws-sdk-go-v2/credentials v1.19.14/go.mod h1:cJKuyWB59Mqi0jM3nFYQRmnHVQIcgoxjEMAbLkpr62w= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.21 h1:NUS3K4BTDArQqNu2ih7yeDLaS3bmHD0YndtA6UP884g= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.21/go.mod h1:YWNWJQNjKigKY1RHVJCuupeWDrrHjRqHm0N9rdrWzYI= github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.21 h1:Rgg6wvjjtX8bNHcvi9OnXWwcE0a2vGpbwmtICOsvcf4= @@ -38,14 +38,14 @@ github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.41.5 h1:z2ayoK3pOvf8ODj/v github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.41.5/go.mod h1:mpZB5HAl4ZIISod9qCi12xZ170TbHX9CCJV5y7nb7QU= github.com/aws/aws-sdk-go-v2/service/signin v1.0.9 h1:QKZH0S178gCmFEgst8hN0mCX1KxLgHBKKY/CLqwP8lg= github.com/aws/aws-sdk-go-v2/service/signin v1.0.9/go.mod h1:7yuQJoT+OoH8aqIxw9vwF+8KpvLZ8AWmvmUWHsGQZvI= -github.com/aws/aws-sdk-go-v2/service/sso v1.30.14 h1:GcLE9ba5ehAQma6wlopUesYg/hbcOhFNWTjELkiWkh4= -github.com/aws/aws-sdk-go-v2/service/sso v1.30.14/go.mod h1:WSvS1NLr7JaPunCXqpJnWk1Bjo7IxzZXrZi1QQCkuqM= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.18 h1:mP49nTpfKtpXLt5SLn8Uv8z6W+03jYVoOSAl/c02nog= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.18/go.mod h1:YO8TrYtFdl5w/4vmjL8zaBSsiNp3w0L1FfKVKenZT7w= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.15 h1:lFd1+ZSEYJZYvv9d6kXzhkZu07si3f+GQ1AaYwa2LUM= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.15/go.mod h1:WSvS1NLr7JaPunCXqpJnWk1Bjo7IxzZXrZi1QQCkuqM= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.19 h1:dzztQ1YmfPrxdrOiuZRMF6fuOwWlWpD2StNLTceKpys= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.19/go.mod h1:YO8TrYtFdl5w/4vmjL8zaBSsiNp3w0L1FfKVKenZT7w= github.com/aws/aws-sdk-go-v2/service/sts v1.41.10 h1:p8ogvvLugcR/zLBXTXrTkj0RYBUdErbMnAFFp12Lm/U= github.com/aws/aws-sdk-go-v2/service/sts v1.41.10/go.mod h1:60dv0eZJfeVXfbT1tFJinbHrDfSJ2GZl4Q//OSSNAVw= -github.com/aws/smithy-go v1.24.2 h1:FzA3bu/nt/vDvmnkg+R8Xl46gmzEDam6mZ1hzmwXFng= -github.com/aws/smithy-go v1.24.2/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc= +github.com/aws/smithy-go v1.24.3 h1:XgOAaUgx+HhVBoP4v8n6HCQoTRDhoMghKqw4LNHsDNg= +github.com/aws/smithy-go v1.24.3/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= @@ -144,8 +144,8 @@ golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= -google.golang.org/api v0.273.1 h1:L7G/TmpAMz0nKx/ciAVssVmWQiOF6+pOuXeKrWVsquY= -google.golang.org/api v0.273.1/go.mod h1:JbAt7mF+XVmWu6xNP8/+CTiGH30ofmCmk9nM8d8fHew= +google.golang.org/api v0.274.0 h1:aYhycS5QQCwxHLwfEHRRLf9yNsfvp1JadKKWBE54RFA= +google.golang.org/api v0.274.0/go.mod h1:JbAt7mF+XVmWu6xNP8/+CTiGH30ofmCmk9nM8d8fHew= google.golang.org/genproto v0.0.0-20260316180232-0b37fe3546d5 h1:JNfk58HZ8lfmXbYK2vx/UvsqIL59TzByCxPIX4TDmsE= google.golang.org/genproto v0.0.0-20260316180232-0b37fe3546d5/go.mod h1:x5julN69+ED4PcFk/XWayw35O0lf/nGa4aNgODCmNmw= google.golang.org/genproto/googleapis/api v0.0.0-20260316180232-0b37fe3546d5 h1:CogIeEXn4qWYzzQU0QqvYBM8yDF9cFYzDq9ojSpv0Js= From f92d1f59f5dc822fdaee29bda42703891ceb5c4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Gonz=C3=A1lez=20Di=20Antonio?= Date: Fri, 3 Apr 2026 11:44:07 +0200 Subject: [PATCH 2/7] chore: update agents instructions --- .github/copilot-instructions.md | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 1b57d10..85d6235 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -46,6 +46,13 @@ make build # Verify build make test # Run tests ``` -If you are intentionally modernizing syntax or APIs for Go 1.26+, run `go fix ./...` manually as a separate step. - -Always keep `README.md` and `docs/` updated for any architectural changes, new commands/flags, removed flags, new packages, or changes to the development workflow. This includes command usage examples, flag tables, and CLI reference sections. +## Pre-PR Checklist + +- never use the `main` branch for development. Always create a new feature branch from `main` for your changes. +- ensure your branch is up to date with `main` before creating a pull request +- write clear and descriptive commit messages that explain the purpose of each change +- ensure all tests pass locally before pushing your changes +- ask the version is going to be released as a patch, minor, or major update and ensure the change log reflects this +- update the `docs/Whats-New.md` file with a summary of the change, including the motivation and impact and the version it will be released in +- ensure the PR description is clear and concise, providing context for reviewers and linking to any relevant issues or documentation +- update the `README.md` file if the change affects usage instructions, configuration, or any other user-facing documentation From 81873b8dff9174c40012a96079f68ef7c18abe6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Gonz=C3=A1lez=20Di=20Antonio?= Date: Fri, 3 Apr 2026 11:45:47 +0200 Subject: [PATCH 3/7] chore: add claude allows permissions --- .claude/settings.json | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .claude/settings.json diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 0000000..080f2f0 --- /dev/null +++ b/.claude/settings.json @@ -0,0 +1,10 @@ +{ + "permissions": { + "allow": [ + "Bash(git checkout:*)", + "Bash(git reset:*)", + "Bash(./build/idpscimcli --help)", + "Bash(./build/idpscim --help)" + ] + } +} From 40816deb61b4c203bfe727ea2213464bd95deb8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Gonz=C3=A1lez=20Di=20Antonio?= Date: Fri, 3 Apr 2026 11:54:21 +0200 Subject: [PATCH 4/7] docs: mark 0.1.x and 0.0.x versions as not supported in SECURITY.md --- SECURITY.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index 393e920..fc6ca98 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,14 +1,17 @@ # Security Policy This project is using [Github CodeQL](https://codeql.github.com/) tool to scan the code vulnerabilities and you can see the report in the pipeline -[![CodeQL Analysis](https://github.com/slashdevops/idp-scim-sync/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/slashdevops/idp-scim-sync/actions/workflows/codeql-analysis.yml) +[![CodeQL Analysis](https://github.com/slashdevops/idp-scim-sync/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/slashdevops/idp-scim-sync/actions/workflows/codeql.yml) + +Since this project is always in development and updated to the last release of `go` and its dependencies, the vulnerabilities are always fixed in the last release, so we will support the last 1 major version and its patches. ## Supported Versions | Version | Supported | | ------- | ------------------ | -| 0.1.x | :white_check_mark: | -| 0.0.x | :white_check_mark: | +| 0.44.x | :white_check_mark: | +| 0.1.x | :x: | +| 0.0.x | :x: | ## Reporting a Vulnerability From 394d6f8f26f419dc79f3e39a672c8d1c01ca634b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Gonz=C3=A1lez=20Di=20Antonio?= Date: Fri, 3 Apr 2026 11:57:12 +0200 Subject: [PATCH 5/7] docs: add missing version entries to supported versions table in SECURITY.md --- SECURITY.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index fc6ca98..80ca5b4 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -10,8 +10,14 @@ Since this project is always in development and updated to the last release of ` | Version | Supported | | ------- | ------------------ | | 0.44.x | :white_check_mark: | -| 0.1.x | :x: | -| 0.0.x | :x: | +| 0.43.x | :x: | +| 0.42.x | :x: | +| 0.32.x | :x: | +| 0.31.x | :x: | +| 0.30.x | :x: | +| 0.2.x | :x: | +| 0.1.x | :x: | +| 0.0.x | :x: | ## Reporting a Vulnerability From ecf0747c22d5fc80ce1e440352da6387a5fb110b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Gonz=C3=A1lez=20Di=20Antonio?= Date: Fri, 3 Apr 2026 12:22:56 +0200 Subject: [PATCH 6/7] docs: refresh project documentation --- README.md | 143 ++++++++----------- docs/AWS-SAM-Template.md | 151 +++++++++++++++++--- docs/AWS-SAM.md | 283 ++++++++++++++++++++++++++----------- docs/Configuration.md | 151 +++++++++++++++----- docs/Demo.md | 30 ++-- docs/Development.md | 152 ++++++++++++++++++-- docs/Release.md | 75 ++++++++-- docs/State-File-example.md | 98 ++++++++----- docs/Using-SSO.md | 121 ++++++++++------ docs/Whats-New.md | 8 ++ docs/idpscim.md | 145 +++++++++++++------ docs/idpscimcli.md | 216 ++++++++++++++++++++-------- 12 files changed, 1125 insertions(+), 448 deletions(-) diff --git a/README.md b/README.md index a075b99..4e5f362 100644 --- a/README.md +++ b/README.md @@ -30,11 +30,11 @@ For a detailed list of new features, improvements, and bug fixes in each release This project is compatible with the latest AWS Lambda runtimes. Since version `v0.0.19`, it uses the `provided.al2` runtime and `arm64` architecture. -| Version Range | AWS Lambda Runtime | Architecture | Deprecation Date | -| -------------------- | ------------------ | ------------------ | ---------------- | -| `<= v0.0.18` | Go 1.x | amd64 (Intel) | 2023-12-31 | +| Version Range | AWS Lambda Runtime | Architecture | Deprecation Date | +| ---------------------- | ------------------ | ------------------ | ---------------- | +| `<= v0.0.18` | Go 1.x | amd64 (Intel) | 2023-12-31 | | `>= v0.0.19 < v0.31.0` | provided.al2 | arm64 (Graviton 2) | 2026-06-30 | -| `>= v0.31.0` | provided.al2023 | arm64 (Graviton 2) | 2029-06-30 | +| `>= v0.31.0` | provided.al2023 | arm64 (Graviton 2) | 2029-06-30 | ## ⚙️ How It Works @@ -48,6 +48,40 @@ For more details on the resources created by the CloudFormation template, please > **Note:** If this is your first time implementing AWS IAM Identity Center, please read [Using SSO](docs/Using-SSO.md). +## Programs + +This repository builds two binaries from the `cmd/` directory: + +| Program | Source | Purpose | +| ------- | ------ | ------- | +| `idpscim` | `cmd/idpscim` | Main synchronization program that runs as the Lambda function, a local CLI, or a container command | +| `idpscimcli` | `cmd/idpscimcli` | Helper CLI used to inspect AWS SCIM and Google Workspace data while validating configuration | + +After `make build`, the binaries are available in `build/`: + +```bash +./build/idpscim --help +./build/idpscimcli --help +``` + +## Documentation Map + +The repository documentation is organized as follows: + +| Document | Purpose | +| ------- | ------- | +| [docs/idpscim.md](docs/idpscim.md) | Main program reference for the `idpscim` sync executable | +| [docs/idpscimcli.md](docs/idpscimcli.md) | Command reference for the `idpscimcli` validation and inspection CLI | +| [docs/Configuration.md](docs/Configuration.md) | Configuration sources, examples, and environment variable usage | +| [docs/AWS-SAM.md](docs/AWS-SAM.md) | Source deployment, Serverless Application Repository update flow, and maintainer publishing workflow | +| [docs/AWS-SAM-Template.md](docs/AWS-SAM-Template.md) | Template parameters, generated resources, and Lambda environment mapping | +| [docs/Development.md](docs/Development.md) | Local development workflow, build steps, tests, and SAM-based cloud testing | +| [docs/Using-SSO.md](docs/Using-SSO.md) | Practical rollout guidance for AWS IAM Identity Center and Google Workspace group design | +| [docs/State-File-example.md](docs/State-File-example.md) | Example state file structure and notes about how sync state is stored | +| [docs/Demo.md](docs/Demo.md) | Visual walkthrough screenshots of the sync process and resulting AWS and Google Workspace data | +| [docs/Release.md](docs/Release.md) | Maintainer release flow based on semantic version tags and GitHub Actions | +| [docs/Whats-New.md](docs/Whats-New.md) | Release notes and notable changes across versions | + ## 🚀 Getting Started The easiest way to deploy and use this project is through the [AWS Serverless Application Repository](https://serverlessrepo.aws.amazon.com/applications/us-east-1/889836709304/idp-scim-sync). @@ -74,112 +108,53 @@ You have several options to use this project: * **AWS Serverless Application Repository (Recommended)** * Deploy the application directly from the [AWS Serverless Application Repository](https://serverlessrepo.aws.amazon.com/applications/us-east-1/889836709304/idp-scim-sync). + * To update an existing deployment to a newer published version, reuse the same original application name that you entered when you first deployed it. Do not use the generated `serverlessrepo-...` stack name. See [docs/AWS-SAM.md](docs/AWS-SAM.md) for the full update flow. * **AWS SAM** * Build and deploy the Lambda function from your local machine. - * **Requirements:** - * [Git](https://git-scm.com/) - * [Go](https://go.dev/learn/) - * [AWS SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html) - * **Commands:** + * Quick start: ```bash -# Set your AWS CLI profile and region export AWS_PROFILE= export AWS_REGION= - -# Validate the template -sam validate - -# Build the project -sam build - -# Deploy with a guided process -sam deploy --guided --capabilities CAPABILITY_IAM CAPABILITY_NAMED_IAM +GIT_VERSION=dev sam build +sam deploy --guided --stack-name idp-scim-sync --capabilities CAPABILITY_IAM CAPABILITY_NAMED_IAM ``` +* For full validation, source deployment, publish, and update guidance, see [docs/AWS-SAM.md](docs/AWS-SAM.md) and [docs/AWS-SAM-Template.md](docs/AWS-SAM-Template.md). + ### Locally * **Build from Source** - * **Requirements:** - * [Git](https://git-scm.com/) - * [Go](https://go.dev/learn/) - * [Make](https://www.gnu.org/software/make/) - * **Commands:** + * Quick start: ```bash -# Compile for your operating system make - -# Cross-compile for Windows, macOS, and Linux -make build-dist +./build/idpscim --help +./build/idpscimcli --help ``` +* **Run the programs** + * **idpscim** runs the actual synchronization logic. + * **idpscimcli** helps you validate your AWS SCIM and Google Workspace configuration before enabling automated sync. + * See [docs/idpscim.md](docs/idpscim.md), [docs/idpscimcli.md](docs/idpscimcli.md), [docs/Configuration.md](docs/Configuration.md), and [docs/Development.md](docs/Development.md) for examples, flags, and the full local workflow. + * **Pre-built Binaries** * Download the binaries from the [GitHub Releases](https://github.com/slashdevops/idp-scim-sync/releases). * **Container Image** * Pull the image from the [GitHub Container Registry](https://github.com/slashdevops/idp-scim-sync/pkgs/container/idp-scim-sync). + * Container build and execution details are documented in [docs/idpscim.md](docs/idpscim.md), [docs/idpscimcli.md](docs/idpscimcli.md), and [docs/Development.md](docs/Development.md). ## Configurable User Fields By default, all optional user attributes are synced from Google Workspace to AWS SSO SCIM. You can control which optional fields are included using the `sync_user_fields` configuration option. -**Available fields:** - -| Field | Description | -| ------------------- | --------------------------------------------------------------------------- | -| `phoneNumbers` | User's phone numbers | -| `addresses` | User's addresses (street, city, region, postal code, country) | -| `title` | User's job title | -| `preferredLanguage` | User's preferred language | -| `locale` | User's locale | -| `timezone` | User's timezone | -| `nickName` | User's nickname | -| `profileURL` | User's profile URL | -| `userType` | User type attribute | -| `enterpriseData` | Enterprise extension (employeeNumber, costCenter, organization, department, division, manager) | - -**Required fields** (always synced, not configurable): `name`, `userName`, `displayName`, `emails`, `active`. - -### Configuration Examples - -**Config file (.idpscim.yaml):** - -```yaml -# Sync only phone numbers, addresses, and enterprise data -sync_user_fields: - - phoneNumbers - - addresses - - enterpriseData -``` - -**Environment variable (Lambda / SAM):** - -```bash -IDPSCIM_SYNC_USER_FIELDS=phoneNumbers,addresses,enterpriseData -``` - -**CLI flag:** - -```bash -idpscim --sync-user-fields phoneNumbers,addresses,enterpriseData -``` - -**SAM template parameter:** - -Set the `SyncUserFields` parameter when deploying: - -```bash -sam deploy --parameter-overrides SyncUserFields=phoneNumbers,addresses,enterpriseData -``` +Supported optional fields include `phoneNumbers`, `addresses`, `title`, `preferredLanguage`, `locale`, `timezone`, `nickName`, `profileURL`, `userType`, and `enterpriseData`. -### Behavior Notes +Required fields are always synchronized: `name`, `userName`, `displayName`, `emails`, and `active`. -* **Default (empty or not set):** When `sync_user_fields` is empty or not configured, all optional fields are synced. This preserves backward compatibility with existing deployments. -* **Specifying fields:** Only the listed fields will be synced. For example, setting `sync_user_fields: [phoneNumbers]` will sync only phone numbers; addresses, enterprise data, and other optional attributes will not be sent to AWS SSO SCIM. -* **Invalid field names:** If an invalid field name is provided, the application will fail at startup with a clear error message listing the unrecognized field. -* **Changing on an existing deployment:** The first sync after modifying this configuration will detect all users as "changed" (due to hash differences) and update them in AWS SSO. This is expected behavior — it will clear the excluded fields from SCIM. +For config file examples, environment variable usage, CLI flags, SAM parameter usage, and behavior notes, see [docs/Configuration.md](docs/Configuration.md) and [docs/idpscim.md](docs/idpscim.md). ## 📦 Repositories @@ -200,12 +175,6 @@ If you are coming from the [awslabs/ssosync](https://github.com/awslabs/ssosync) * This project only implements filtering for Google Workspace Groups, not Users. * This project supports selecting which optional user attributes to sync via `--sync-user-fields` (e.g., phone numbers, addresses, enterprise data). * The flag names are different. -* Not all features of `ssosync` are implemented here, and they may not be in the future. - -## 🧩 Components - -* **idpscim**: A program for keeping AWS IAM Identity Center groups and users synced with your Google Workspace directory. See the [idpscim documentation](docs/idpscim.md) for more details. -* **idpscimcli**: A command-line tool to check and validate some of the functionalities implemented in `idpscim`. See the [idpscimcli documentation](docs/idpscimcli.md) for more details. ## 📄 License diff --git a/docs/AWS-SAM-Template.md b/docs/AWS-SAM-Template.md index 114cc03..1996510 100644 --- a/docs/AWS-SAM-Template.md +++ b/docs/AWS-SAM-Template.md @@ -1,23 +1,132 @@ # AWS SAM Template -This project use [AWS SAM](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification.html), a tool for creating serverless applications. This facilitates the creation of serverless applications that can be deployed to [AWS Lambda](https://aws.amazon.com/lambda/) and others different resources using [AWS CloudFormation.](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/Welcome.html). - -## Resources - -The file [template.yaml](https://github.com/slashdevops/idp-scim-sync/blob/main/template.yaml) after being transformed by the [AWS SAM package command](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-cli-command-reference-sam-package.html) in `packaged.yaml` creates the following resources: - -| # | Type | CloudFormation Logical ID | -| --- | --------------------------- | ------------------------------------------ | -| 1 | AWS::SecretsManager::Secret | AWSGWSServiceAccountFileSecret | -| 2 | AWS::SecretsManager::Secret | AWSGWSUserEmailSecret | -| 3 | AWS::SecretsManager::Secret | AWSSCIMAccessTokenSecret | -| 4 | AWS::SecretsManager::Secret | AWSSCIMEndpointSecret | -| 5 | AWS::S3::Bucket | Bucket | -| 6 | AWS::S3::BucketPolicy | BucketPolicy | -| 7 | AWS::KMS::Key | KMSKey | -| 8 | AWS::KMS::Alias | KMSKeyAlias | -| 9 | AWS::Lambda::Function | LambdaFunction | -| 10 | AWS::Logs::LogGroup | LambdaFunctionLogGroup | -| 11 | AWS::IAM::Role | LambdaFunctionRole | -| 12 | AWS::Events::Rule | LambdaFunctionSyncScheduledEvent | -| 13 | AWS::Lambda::Permission | LambdaFunctionSyncScheduledEventPermission | +This project uses [AWS SAM](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification.html) to define the Lambda-based deployment of `idp-scim-sync`. The source template is [template.yaml](../template.yaml). + +## What The Template Does + +The template deploys the main `idpscim` program as a scheduled Lambda function that synchronizes Google Workspace groups and users into AWS IAM Identity Center through the SCIM API. + +At a high level, the template does the following: + +- Creates the Lambda function and schedules it with EventBridge. +- Stores sensitive credentials in Secrets Manager. +- Creates an encrypted S3 bucket for the sync state file. +- Creates the IAM role and permissions required by the Lambda function. +- Creates the CloudWatch log group used by the function. +- Adds metadata required to publish the application to the AWS Serverless Application Repository. + +## Build And Publish Metadata + +The template includes two important metadata blocks: + +| Metadata | Purpose | +| --- | --- | +| `AWS::Serverless::Function` `BuildMethod: makefile` | Tells `sam build` to invoke `build-LambdaFunction` from [Makefile](../Makefile) | +| `AWS::ServerlessRepo::Application` | Provides the public application metadata used by the AWS Serverless Application Repository | + +This means the SAM build for this project is not a generic Go Lambda build. It is repository-specific and intentionally compiles [cmd/idpscim/main.go](../cmd/idpscim/main.go) into a `bootstrap` binary. + +## Parameters + +The template parameters are grouped into three practical areas. + +### Runtime And Sync Behavior + +| Parameter | Purpose | Default | +| --- | --- | --- | +| `ScheduleExpression` | EventBridge schedule for the Lambda execution | `rate(15 minutes)` | +| `SyncMethod` | Sync strategy implemented by the application | `groups` | +| `SyncUserFields` | Optional user attributes to synchronize | empty | +| `GWSGroupsFilter` | Google Workspace group filter | empty | +| `LogLevel` | Application log level | `info` | +| `LogFormat` | Application log format | `json` | +| `MemorySize` | Lambda memory allocation | `256` | +| `Timeout` | Lambda timeout in seconds | `300` | +| `Runtime` | Lambda runtime | `provided.al2023` | +| `Architecture` | Lambda CPU architecture | `arm64` | +| `LambdaFunctionHandler` | Lambda handler entrypoint | `bootstrap` | +| `LambdaFunctionName` | Lambda function name | `idp-scim-sync` | +| `LogGroupName` | CloudWatch log group name | `/aws/lambda/idp-scim-sync` | +| `LogGroupRetentionDays` | CloudWatch log retention | `7` | +| `RoleNameSuffix` | Optional suffix to avoid IAM role name collisions | empty | + +### State File Storage + +| Parameter | Purpose | Default | +| --- | --- | --- | +| `BucketNamePrefix` | Prefix used to build the state bucket name | `idp-scim-sync-state` | +| `BucketKey` | S3 object key for the saved sync state | `data/state.json` | + +The final bucket name is assembled as: + +```text +-- +``` + +### Credentials And Secret Names + +| Parameter | Purpose | Default | +| --- | --- | --- | +| `GWSServiceAccountFile` | Google Workspace service account JSON contents | none | +| `GWSServiceAccountFileSecretName` | Secret name for that JSON | `IDPSCIM_GWSServiceAccountFile` | +| `GWSUserEmail` | Delegated Google Workspace user email | none | +| `GWSUserEmailSecretName` | Secret name for that email | `IDPSCIM_GWSUserEmail` | +| `SCIMEndpoint` | AWS IAM Identity Center SCIM endpoint | none | +| `SCIMEndpointSecretName` | Secret name for the SCIM endpoint | `IDPSCIM_SCIMEndpoint` | +| `SCIMAccessToken` | AWS IAM Identity Center SCIM access token | none | +| `SCIMAccessTokenSecretName` | Secret name for the SCIM token | `IDPSCIM_SCIMAccessToken` | + +The sensitive input values are stored in Secrets Manager, and the Lambda function receives the secret names through environment variables. The function then resolves the actual secret values at runtime. + +## Resources Created + +After packaging and deployment, the template creates the following resources: + +| # | Type | Logical ID | Purpose | +| --- | --- | --- | --- | +| 1 | `AWS::Serverless::Function` | `LambdaFunction` | Runs the sync logic from `idpscim` | +| 2 | `AWS::IAM::Role` | `LambdaFunctionRole` | Grants Lambda access to Secrets Manager, S3, KMS, logs, and X-Ray | +| 3 | `AWS::SecretsManager::Secret` | `AWSGWSServiceAccountFileSecret` | Stores Google Workspace credentials | +| 4 | `AWS::SecretsManager::Secret` | `AWSGWSUserEmailSecret` | Stores the delegated Google Workspace email | +| 5 | `AWS::SecretsManager::Secret` | `AWSSCIMEndpointSecret` | Stores the AWS SCIM endpoint | +| 6 | `AWS::SecretsManager::Secret` | `AWSSCIMAccessTokenSecret` | Stores the AWS SCIM token | +| 7 | `AWS::KMS::Key` | `KMSKey` | Encrypts the S3 state bucket | +| 8 | `AWS::KMS::Alias` | `KMSKeyAlias` | Stable alias for the KMS key | +| 9 | `AWS::S3::Bucket` | `Bucket` | Stores the sync state file | +| 10 | `AWS::S3::BucketPolicy` | `BucketPolicy` | Restricts access to the state bucket and enforces TLS | +| 11 | `AWS::Logs::LogGroup` | `LambdaFunctionLogGroup` | Stores Lambda logs | + +The scheduled trigger is defined inside the `AWS::Serverless::Function` as a SAM `Schedule` event, which expands into the EventBridge rule and the matching Lambda invoke permission during transformation. + +## Lambda Environment + +The Lambda function receives configuration through environment variables mapped from template parameters and created secret names. + +Important environment variables include: + +- `IDPSCIM_LOG_LEVEL` +- `IDPSCIM_LOG_FORMAT` +- `IDPSCIM_SYNC_METHOD` +- `IDPSCIM_SYNC_USER_FIELDS` +- `IDPSCIM_GWS_GROUPS_FILTER` +- `IDPSCIM_AWS_S3_BUCKET_NAME` +- `IDPSCIM_AWS_S3_BUCKET_KEY` +- `IDPSCIM_GWS_USER_EMAIL_SECRET_NAME` +- `IDPSCIM_GWS_SERVICE_ACCOUNT_FILE_SECRET_NAME` +- `IDPSCIM_AWS_SCIM_ENDPOINT_SECRET_NAME` +- `IDPSCIM_AWS_SCIM_ACCESS_TOKEN_SECRET_NAME` + +## Outputs + +The template exports two useful outputs: + +| Output | Description | +| --- | --- | +| `LambdaFunctionArn` | ARN of the deployed Lambda function | +| `LambdaFunctionName` | Name of the deployed Lambda function | + +## Related Documentation + +- [AWS-SAM.md](AWS-SAM.md) for deployment, update, and publish workflows +- [Configuration.md](Configuration.md) for application configuration behavior +- [README.md](../README.md) for high-level usage guidance diff --git a/docs/AWS-SAM.md b/docs/AWS-SAM.md index 03af2cb..7c6c93c 100644 --- a/docs/AWS-SAM.md +++ b/docs/AWS-SAM.md @@ -1,112 +1,237 @@ # AWS SAM -This document is a reference to the [AWS Serverless Application Model (SAM)](https://aws.amazon.com/serverless/sam/) and how to use it to deploy a `serverless` applications. +This repository uses [AWS Serverless Application Model (AWS SAM)](https://docs.aws.amazon.com/en_en/serverless-application-model/latest/developerguide/what-is-sam.html) in two ways: -## Preparation +1. To deploy `idp-scim-sync` privately from source into your own AWS account. +2. To publish public versions to the [AWS Serverless Application Repository](https://serverlessrepo.aws.amazon.com/applications/us-east-1/889836709304/idp-scim-sync). -first export the environment variables +The same [template.yaml](../template.yaml) drives both workflows. + +## How this repository uses SAM + +- [template.yaml](../template.yaml) defines the Lambda function, EventBridge schedule, Secrets Manager secrets, S3 state bucket, KMS key, IAM role, and CloudWatch log group. +- The template includes `AWS::ServerlessRepo::Application` metadata so the application can be published to the AWS Serverless Application Repository. +- The Lambda build uses `Metadata: BuildMethod: makefile`, so `sam build` calls the `build-LambdaFunction` target from [Makefile](../Makefile). +- That build target compiles [cmd/idpscim/main.go](../cmd/idpscim/main.go) into a `bootstrap` binary for the `provided.al2023` runtime on `arm64`. +- Maintainer publishing is automated in [.github/workflows/aws-sam.yml](../.github/workflows/aws-sam.yml). + +## Prerequisites + +Before using SAM in this repository, install and configure the following: + +- [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) +- [AWS SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html) +- [Go](https://go.dev/doc/install) +- `make` +- AWS credentials with permission to create CloudFormation, Lambda, EventBridge, IAM, Secrets Manager, S3, CloudWatch Logs, and KMS resources +- Google Workspace service account credentials and delegated user email +- AWS IAM Identity Center SCIM endpoint and access token + +Recommended environment variables: ```bash -export AWS_PROFILE= -export AWS_REGION= +export AWS_PROFILE= +export AWS_REGION=us-east-1 +``` + +For publishing public versions, you also need: -# only needed to Package and Deploy -export SAM_APP_BUCKET= -export SAM_APP_VERSION= +```bash +export SAM_APP_BUCKET= +export SAM_APP_VERSION= ``` -## Deployment +## Validate And Build -Validate and Build +Use SAM and CloudFormation validation before deploying: ```bash -aws cloudformation validate-template --template-body file://template.yaml 1>/dev/null --profile $AWS_PROFILE -sam validate --profile $AWS_PROFILE +aws cloudformation validate-template \ + --template-body file://template.yaml \ + --profile "$AWS_PROFILE" + +sam validate \ + --profile "$AWS_PROFILE" \ + --region "$AWS_REGION" + +GIT_VERSION=dev sam build \ + --profile "$AWS_PROFILE" \ + --region "$AWS_REGION" +``` + +`sam build` creates `.aws-sam/build/LambdaFunction/bootstrap` by invoking the repository `Makefile`. + +## Deploy From Source Into Your AWS Account + +For private deployments from source, use `sam deploy --guided` the first time. It is the safest option because this template includes secret values such as the Google Workspace credential JSON and the SCIM token. + +```bash +sam deploy --guided \ + --stack-name idp-scim-sync \ + --capabilities CAPABILITY_IAM CAPABILITY_NAMED_IAM \ + --profile "$AWS_PROFILE" \ + --region "$AWS_REGION" +``` + +During the guided prompts, provide at least these required values: + +| Parameter | Purpose | +| --- | --- | +| `GWSServiceAccountFile` | Full contents of the Google Workspace service account JSON | +| `GWSUserEmail` | Delegated Google Workspace administrator or service user email | +| `SCIMEndpoint` | AWS IAM Identity Center SCIM endpoint URL | +| `SCIMAccessToken` | AWS IAM Identity Center SCIM bearer token | + +Common optional parameters you will usually adjust: + +| Parameter | Purpose | Default | +| --- | --- | --- | +| `GWSGroupsFilter` | Restrict which Google Workspace groups are synchronized | empty | +| `SyncUserFields` | Comma-separated optional user attributes to sync | empty = all supported fields | +| `ScheduleExpression` | EventBridge execution schedule | `rate(15 minutes)` | +| `BucketNamePrefix` | Prefix for the state bucket name | `idp-scim-sync-state` | +| `BucketKey` | S3 object key for the state file | `data/state.json` | +| `MemorySize` | Lambda memory | `256` | +| `Timeout` | Lambda timeout in seconds | `300` | +| `LogLevel` | Application log level | `info` | +| `LogFormat` | Lambda log format | `json` | + +After the first guided deploy, SAM stores the deployment configuration. Subsequent updates are usually just: -sam build --profile $AWS_PROFILE +```bash +GIT_VERSION=dev sam build \ + --profile "$AWS_PROFILE" \ + --region "$AWS_REGION" + +sam deploy \ + --stack-name idp-scim-sync \ + --capabilities CAPABILITY_IAM CAPABILITY_NAMED_IAM \ + --profile "$AWS_PROFILE" \ + --region "$AWS_REGION" ``` -Deploy (Local way) +## Update An Existing Deployment From The AWS Serverless Application Repository + +This project is also published to the public AWS Serverless Application Repository: + +- [AWS Serverless Application Repository application page](https://serverlessrepo.aws.amazon.com/applications/us-east-1/889836709304/idp-scim-sync) + +The important AWS behavior to remember is this: + +- When you deploy an application from the AWS Serverless Application Repository, AWS creates a CloudFormation stack whose actual name is prefixed with `serverlessrepo-`. +- When you update that application later, you must reuse the original application name or stack name that you entered when you first deployed it. +- Do not enter the generated `serverlessrepo-...` stack name during the update flow. + +Example: + +- Original name you entered: `idp-scim-sync` +- Actual CloudFormation stack created by AWS: `serverlessrepo-idp-scim-sync` +- Name to use for future updates: `idp-scim-sync` + +### Console Update Flow + +For most users, the console update flow is the clearest option: + +1. Open the published application page in the AWS Serverless Application Repository. +2. Choose `Deploy` again for the same application. +3. Enter the same application name you used the first time, without the `serverlessrepo-` prefix. +4. Select the newer published application version. +5. Keep the existing parameter values or change them as needed. +6. Acknowledge IAM capabilities if prompted. +7. Deploy the update. + +Use this flow when you want to move to a new published version without building from source locally. + +### AWS CLI Update Flow + +If you automate updates, the AWS Serverless Application Repository docs use a CloudFormation change set flow: + +1. Inspect the application and required capabilities. +2. Create a CloudFormation change set for the same original stack name. +3. Execute that change set. + +Example skeleton: ```bash -sam deploy --guided --capabilities CAPABILITY_IAM --capabilities CAPABILITY_NAMED_IAM --profile $AWS_PROFILE +export AWS_REGION=us-east-1 +export APPLICATION_ID=arn:aws:serverlessrepo:us-east-1:889836709304:applications/idp-scim-sync + +aws serverlessrepo get-application \ + --application-id "$APPLICATION_ID" \ + --region "$AWS_REGION" + +CHANGE_SET_ID=$(aws serverlessrepo create-cloud-formation-change-set \ + --application-id "$APPLICATION_ID" \ + --stack-name idp-scim-sync \ + --capabilities CAPABILITY_IAM CAPABILITY_NAMED_IAM \ + --region "$AWS_REGION" \ + --query ChangeSetId \ + --output text) + +aws cloudformation execute-change-set \ + --change-set-name "$CHANGE_SET_ID" \ + --region "$AWS_REGION" ``` -## Publish +If your deployment requires explicit parameter overrides, include them when creating the change set. Reuse the same stack name you originally deployed with, not the generated `serverlessrepo-...` name. -Package and Publish (Only project Owners) +## Publish A New Public Version + +This section is only for project maintainers who publish new versions of the application. + +Package the application artifacts: ```bash sam package \ --output-template-file packaged.yaml \ - --s3-bucket $SAM_APP_BUCKET \ - --profile $AWS_PROFILE + --s3-bucket "$SAM_APP_BUCKET" \ + --profile "$AWS_PROFILE" \ + --region "$AWS_REGION" ``` -Buy default this is private the first time and depends on `AWS_REGION` +Publish the packaged template as a new semantic version: ```bash -#export AWS_PUBLIC_REGIONS=($(aws ec2 describe-regions | jq -c -r '.Regions[] | .RegionName' | tr '\n' ' ')) - -export AWS_PUBLIC_REGIONS=(\ -us-east-1 \ -) - -for AWS_PUBLIC_REGION in $AWS_PUBLIC_REGIONS; do - echo "Publishing in $AWS_PUBLIC_REGION ..." - sam publish \ - --semantic-version $SAM_APP_VERSION \ - --template packaged.yaml \ - --region $AWS_PUBLIC_REGION \ - --profile $AWS_PROFILE - - sleep 2 - - export AWS_SAM_APP_ARN=$(\ - aws serverlessrepo list-applications \ - --max-items 100 \ - --region $AWS_PUBLIC_REGION \ - --profile $AWS_PROFILE \ - | jq -c '.Applications[] | select(.ApplicationId | contains("idp-scim-sync"))' \ - | jq -r '.ApplicationId' \ - ) - - sleep 2 - - aws serverlessrepo put-application-policy \ - --application-id $AWS_SAM_APP_ARN \ - --statements Principals='*',Actions='Deploy' \ - --region $AWS_PUBLIC_REGION \ - --profile $AWS_PROFILE - - sleep 1 -done +sam publish \ + --semantic-version "$SAM_APP_VERSION" \ + --template packaged.yaml \ + --region us-east-1 \ + --profile "$AWS_PROFILE" ``` -Delete Application +Then make the published application deployable by other AWS accounts: + +```bash +AWS_SAM_APP_ARN=$(aws serverlessrepo list-applications \ + --max-items 100 \ + --region us-east-1 \ + --profile "$AWS_PROFILE" \ + | jq -c '.Applications[] | select(.ApplicationId | contains("idp-scim-sync"))' \ + | jq -r '.ApplicationId') + +aws serverlessrepo put-application-policy \ + --application-id "$AWS_SAM_APP_ARN" \ + --statements Principals='*',Actions='Deploy' \ + --region us-east-1 \ + --profile "$AWS_PROFILE" +``` + +The repository CI workflow in [.github/workflows/aws-sam.yml](../.github/workflows/aws-sam.yml) already automates this process for tagged releases. + +## Remove A Published Application + +If you need to delete the published application from the AWS Serverless Application Repository: ```bash -export AWS_PUBLIC_REGIONS=(\ -us-east-1 \ -) - -for AWS_PUBLIC_REGION in $AWS_PUBLIC_REGIONS; do - echo "Deleting in $AWS_PUBLIC_REGION ..." - - export AWS_SAM_APP_ARN=$(\ - aws serverlessrepo list-applications \ - --max-items 100 \ - --region $AWS_PUBLIC_REGION \ - --profile $AWS_PROFILE \ - | jq -c '.Applications[] | select(.ApplicationId | contains("idp-scim-sync"))' \ - | jq -r '.ApplicationId' \ - ) - - sleep 1 - - aws serverlessrepo delete-application \ - --application-id $AWS_SAM_APP_ARN \ - --region $AWS_PUBLIC_REGION \ - --profile $AWS_PROFILE -done +AWS_SAM_APP_ARN=$(aws serverlessrepo list-applications \ + --max-items 100 \ + --region us-east-1 \ + --profile "$AWS_PROFILE" \ + | jq -c '.Applications[] | select(.ApplicationId | contains("idp-scim-sync"))' \ + | jq -r '.ApplicationId') + +aws serverlessrepo delete-application \ + --application-id "$AWS_SAM_APP_ARN" \ + --region us-east-1 \ + --profile "$AWS_PROFILE" ``` diff --git a/docs/Configuration.md b/docs/Configuration.md index 4024cff..82fdf5e 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -1,17 +1,37 @@ # Configuration -The `idpscim` program could be configured using three ways: `configuration file`, `command line arguments` and `environment variables`. +This document describes how to configure the project binaries, especially `idpscim`, which is the program executed by Lambda and by the local sync CLI. -NOTES: +Use this document together with: -* The configuration could result in a merge of the three sources. -* The precedence order is `configuration file`, `command line arguments` and `environment variables`. +* [idpscim.md](idpscim.md) for the executable and flag overview +* [idpscimcli.md](idpscimcli.md) for the validation CLI commands +* [AWS-SAM.md](AWS-SAM.md) for Lambda deployment examples -## Prerequisites +## Configuration Sources -To have access to the `AWS Resources` like `AWS S3` you will need `AWS Credentials`, so, before execute the `idpscim` or `idpscimcli` program use one of the following configuration methods: +The project uses a combination of Cobra flags and Viper configuration loading. -Using `AWS_ACCESS_KEY` +In practice, you have these input sources: + +* Built-in defaults from the Go code +* A config file such as `.idpscim.yaml` +* Environment variables prefixed with `IDPSCIM_` +* Command-line flags for the active command + +Because some settings can be supplied from more than one place, the safest operating model is to choose one primary source for each deployment style: + +* Local development: use a config file plus a small number of CLI flags when needed +* AWS SAM and Lambda: use environment variables and secret names from the template +* One-off testing: use CLI flags directly + +## AWS Credentials + +Both `idpscim` and `idpscimcli` rely on the AWS SDK default credential chain when they need AWS access. + +Common approaches: + +Using direct credentials: ```bash export AWS_ACCESS_KEY_ID="" @@ -19,85 +39,138 @@ export AWS_SECRET_ACCESS_KEY="" export AWS_REGION="" ``` -Using `profiles` +Using a profile: ```bash -export AWS_PROFILE="slashdevops" +export AWS_PROFILE="my-profile" export AWS_REGION="" export AWS_ROLE_SESSION_NAME="idp-scim-sync" ``` -__NOTES:__ +Profiles with role assumption and MFA are supported by the AWS SDK as long as your local AWS CLI configuration is valid. + +## Main `idpscim` Settings + +The main sync program uses these configuration groups: -* This support profiles with and without `role` and `mfa` +| Group | Settings | +| --- | --- | +| Logging | `log_level`, `log_format`, `debug` | +| Google Workspace | `gws_service_account_file`, `gws_user_email`, `gws_groups_filter` | +| Google Workspace secret names | `gws_service_account_file_secret_name`, `gws_user_email_secret_name` | +| AWS SCIM | `aws_scim_endpoint`, `aws_scim_access_token` | +| AWS SCIM secret names | `aws_scim_endpoint_secret_name`, `aws_scim_access_token_secret_name` | +| State repository | `aws_s3_bucket_name`, `aws_s3_bucket_key` | +| Sync behavior | `sync_method`, `sync_user_fields`, `use_secrets_manager` | -## Configuration file +Important notes: -create a `.idpscim.yaml` file in the `$HOME/` directory or in the same path where the `idpscim` program is. +* `sync_method` currently supports `groups` +* `sync_user_fields` is optional; when empty, all supported optional user attributes are synced +* `use_secrets_manager=true` tells the program to resolve credential values from AWS Secrets Manager using the configured secret names +* The code default for `aws_s3_bucket_key` is `state.json`, while the AWS SAM template overrides it to `data/state.json` unless you change the template parameter + +## Config File Example + +For local usage, place `.idpscim.yaml` in your home directory, the current working directory, or point to a file explicitly with `--config-file`. ```yaml log_level: debug log_format: text gws_service_account_file: /path/to/gws_service_account.json -gws_user_email: my.user@gws-email.com +gws_user_email: admin@example.com gws_groups_filter: - - 'name:AWS* email:aws*' - - 'email:administrators*' + - 'name:AWS*' + - 'email:aws-admins@example.com' -aws_scim_endpoint: https://scim.eu-west-1.amazonaws.com//scim/v2/ +aws_scim_endpoint: https://example.awsapps.com/scim/v2/ aws_scim_access_token: -aws_s3_bucket_name: my-bucket +aws_s3_bucket_name: idp-scim-sync-state-123456789012-us-east-1 aws_s3_bucket_key: data/state.json sync_method: groups +sync_user_fields: + - phoneNumbers + - addresses + - enterpriseData use_secrets_manager: false ``` -then run the `idpscim` program +Run with the default config file name: ```bash -./idpscim +./build/idpscim ``` -or create a `.yaml` then run the `idpscim` program with the `--config-file` option. +Or point to a specific file: ```bash -./idpscim --config-file .yaml +./build/idpscim --config-file /path/to/custom.idpscim.yaml ``` -## Command line arguments +## CLI Example + +Use flags directly for one-off tests or automation: ```bash -# execute the program with the following arguments -./idpscim \ - --aws-s3-bucket-name "my-bucket" \ +./build/idpscim \ + --aws-s3-bucket-name "idp-scim-sync-state-123456789012-us-east-1" \ --aws-s3-bucket-key "data/state.json" \ --aws-scim-access-token "" \ - --aws-scim-endpoint "https://scim.eu-west-1.amazonaws.com//scim/v2/" \ + --aws-scim-endpoint "https://example.awsapps.com/scim/v2/" \ --gws-service-account-file "/path/to/gws_service_account.json" \ - --gws-user-email "my.user@gws-email.com" \ - --gws-groups-filter 'name:AWS* email:aws*' \ - --gws-groups-filter 'email:administrators*' \ - --sync-method 'groups' + --gws-user-email "admin@example.com" \ + --gws-groups-filter 'name:AWS*' \ + --sync-method groups \ + --sync-user-fields phoneNumbers,addresses,enterpriseData \ --log-level debug ``` -## Environment variables +## Environment Variable Example + +Environment variables are especially useful for AWS SAM and Lambda deployments. ```bash -# first export the environment variables -export IDPSCIM_AWS_S3_BUCKET_NAME="my-bucket" +export IDPSCIM_AWS_S3_BUCKET_NAME="idp-scim-sync-state-123456789012-us-east-1" export IDPSCIM_AWS_S3_BUCKET_KEY="data/state.json" export IDPSCIM_AWS_SCIM_ACCESS_TOKEN="" -export IDPSCIM_AWS_SCIM_ENDPOINT="https://scim.eu-west-1.amazonaws.com//scim/v2/" +export IDPSCIM_AWS_SCIM_ENDPOINT="https://example.awsapps.com/scim/v2/" export IDPSCIM_GWS_SERVICE_ACCOUNT_FILE="/path/to/gws_service_account.json" -export IDPSCIM_GWS_USER_EMAIL="my.user@gws-email.com" -export IDPSCIM_GWS_GROUPS_FILTER='name:AWS* email:aws*','email:administrators*' +export IDPSCIM_GWS_USER_EMAIL="admin@example.com" +export IDPSCIM_GWS_GROUPS_FILTER='name:AWS*' export IDPSCIM_SYNC_METHOD="groups" +export IDPSCIM_SYNC_USER_FIELDS="phoneNumbers,addresses,enterpriseData" export IDPSCIM_LOG_LEVEL="debug" -# then execute the program -./idpscim +./build/idpscim +``` + +If you want runtime secret resolution instead of passing raw credentials: + +```bash +export IDPSCIM_USE_SECRETS_MANAGER=true +export IDPSCIM_GWS_SERVICE_ACCOUNT_FILE_SECRET_NAME="IDPSCIM_GWSServiceAccountFile" +export IDPSCIM_GWS_USER_EMAIL_SECRET_NAME="IDPSCIM_GWSUserEmail" +export IDPSCIM_AWS_SCIM_ENDPOINT_SECRET_NAME="IDPSCIM_SCIMEndpoint" +export IDPSCIM_AWS_SCIM_ACCESS_TOKEN_SECRET_NAME="IDPSCIM_SCIMAccessToken" ``` + +## `idpscimcli` Notes + +`idpscimcli` uses the same config file name and some of the same fields, but it is command-oriented: + +* AWS SCIM inspection commands usually rely on `--aws-scim-endpoint` and `--aws-scim-access-token` +* Google Workspace inspection commands usually rely on `--gws-service-account-file` and `--gws-user-email` +* Output formatting is controlled with `--output-format` +* Request timeout is controlled with `--timeout` + +For the exact command tree and examples, see [idpscimcli.md](idpscimcli.md). + +## Related Documentation + +* [idpscim.md](idpscim.md) +* [idpscimcli.md](idpscimcli.md) +* [AWS-SAM.md](AWS-SAM.md) +* [Development.md](Development.md) diff --git a/docs/Demo.md b/docs/Demo.md index de820e5..31f279c 100644 --- a/docs/Demo.md +++ b/docs/Demo.md @@ -1,4 +1,8 @@ -# Demo images +# Demo + +This page contains screenshots of a typical synchronization workflow and the resulting objects in Google Workspace, AWS IAM Identity Center, and the S3 state repository. + +Use it as a visual companion to the deployment and configuration guides. ## First time sync @@ -18,30 +22,36 @@ ![AWS Bucket file](images/demo/state-file.png) -## Google Workspace data +## Google Workspace Data -### Users +### Google Workspace Users ![Google Workspace users](images/demo/gws-users.png) -### Groups +### Google Workspace Groups ![Google Workspace groups](images/demo/gws-groups.png) -### Group Developers +### Google Workspace Group Developers ![Google Workspace groups](images/demo/gws-groups-developers.png) -## AWS SSO data +## AWS IAM Identity Center Data -### Users +### AWS IAM Identity Center Users ![AWS SSO users](images/demo/aws-users.png) -### Groups +### AWS IAM Identity Center Groups ![AWS SSO groups](images/demo/aws-groups.png) -### Group Developers +### AWS IAM Identity Center Group Developers + +![AWS SSO groups](images/demo/aws-groups-developers.png) + +## Related Documentation -![AWS SSO groups](images/demo/aws-groups-developers.png) \ No newline at end of file +* [README.md](../README.md) +* [AWS-SAM.md](AWS-SAM.md) +* [State-File-example.md](State-File-example.md) diff --git a/docs/Development.md b/docs/Development.md index ce2dfec..3996a08 100644 --- a/docs/Development.md +++ b/docs/Development.md @@ -1,28 +1,156 @@ -# Development references +# Development -## Container Registry +This document covers the day-to-day development workflow for this repository, including local Go development, the two CLI programs built from `cmd/`, and the AWS SAM workflow used to deploy the Lambda function. -Container images are published to [GitHub Container Registry](https://github.com/slashdevops/idp-scim-sync/pkgs/container/idp-scim-sync) (ghcr.io) using [podman](https://podman.io/). +## Prerequisites -### Build locally +Install the following tools before contributing: + +- [Git](https://git-scm.com/) +- [Go](https://go.dev/doc/install) +- `make` +- [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) if you want to deploy or test in AWS +- [AWS SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html) if you want to work with the serverless deployment +- [podman](https://podman.io/) if you want to build or publish the container image + +## Main Entry Points + +This repository builds two user-facing programs: + +| Program | Source directory | Purpose | +| --- | --- | --- | +| `idpscim` | [cmd/idpscim](../cmd/idpscim) | Main synchronization program used by Lambda, local CLI execution, and the container image | +| `idpscimcli` | [cmd/idpscimcli](../cmd/idpscimcli) | Helper CLI used to inspect Google Workspace and AWS SCIM data while validating configuration | + +Local builds are written to `build/`: + +- `build/idpscim` +- `build/idpscimcli` + +## Recommended Local Workflow + +Run the repository quality checks in the same order the project expects: + +```bash +make go-fmt +make go-betteralign +golangci-lint run ./... +make build +make test +``` + +## Build And Run The Programs Locally + +Build both binaries: + +```bash +make build +``` + +Show the help for each program: + +```bash +./build/idpscim --help +./build/idpscimcli --help +``` + +Useful `idpscimcli` validation commands during development: + +```bash +./build/idpscimcli aws service config --help +./build/idpscimcli aws groups list --help +./build/idpscimcli gws groups list --help +./build/idpscimcli gws groups members list --help +./build/idpscimcli gws users list --help +``` + +## Build Distribution Artifacts + +To cross-compile the binaries for the supported operating systems and architectures: ```bash -# Build cross-platform binaries make build-dist +``` -# Build container images (requires podman) -GIT_VERSION=test make container-build +This writes the artifacts to `dist/`. + +## Use AWS SAM During Development -# Verify +AWS SAM is the deployment path for the Lambda version of `idpscim`. + +### Validate And Build + +```bash +export AWS_PROFILE= +export AWS_REGION=us-east-1 + +aws cloudformation validate-template \ + --template-body file://template.yaml \ + --profile "$AWS_PROFILE" + +sam validate \ + --profile "$AWS_PROFILE" \ + --region "$AWS_REGION" + +GIT_VERSION=dev sam build \ + --profile "$AWS_PROFILE" \ + --region "$AWS_REGION" +``` + +### First Deploy + +Use the guided workflow the first time so you can enter the required parameters interactively: + +```bash +sam deploy --guided \ + --stack-name idp-scim-sync \ + --capabilities CAPABILITY_IAM CAPABILITY_NAMED_IAM \ + --profile "$AWS_PROFILE" \ + --region "$AWS_REGION" +``` + +### Update An Existing Development Stack + +After the first guided deployment, iterate with: + +```bash +GIT_VERSION=dev sam build \ + --profile "$AWS_PROFILE" \ + --region "$AWS_REGION" + +sam deploy \ + --stack-name idp-scim-sync \ + --capabilities CAPABILITY_IAM CAPABILITY_NAMED_IAM \ + --profile "$AWS_PROFILE" \ + --region "$AWS_REGION" +``` + +Use this when you want to validate application changes against real AWS resources. + +## Container Workflow + +Container images are published to [GitHub Container Registry](https://github.com/slashdevops/idp-scim-sync/pkgs/container/idp-scim-sync) using `podman`. + +Build locally: + +```bash +make build-dist +GIT_VERSION=test make container-build podman images | grep idp-scim-sync ``` -### Publish to ghcr.io +Publish: ```bash -# Login -REPOSITORY_REGISTRY_TOKEN= REPOSITORY_REGISTRY_USERNAME= make container-login +REPOSITORY_REGISTRY_TOKEN= \ +REPOSITORY_REGISTRY_USERNAME= \ +make container-login -# Publish GIT_VERSION= make container-publish ``` + +## Related Documentation + +- [AWS-SAM.md](AWS-SAM.md) for private deploys, SAR updates, and public publishing +- [idpscim.md](idpscim.md) for the main sync program +- [idpscimcli.md](idpscimcli.md) for the validation CLI diff --git a/docs/Release.md b/docs/Release.md index 8892948..bbedf96 100644 --- a/docs/Release.md +++ b/docs/Release.md @@ -1,18 +1,75 @@ # Release -This document explain the basic of how to release a new version of the project. +This document describes the maintainer release flow for this repository. -## Process +The release automation is driven by the GitHub Actions workflow in [../.github/workflows/release.yml](../.github/workflows/release.yml), which runs when a tag matching `v..` is pushed. -The release process is divided into three steps: +## What The Release Workflow Does -1. Create a new git tag -2. This new tag is pushed to the remote repository -3. The Release Pipeline is triggered +When you push a semantic version tag such as `v0.44.1`, the release workflow: -## Commands +1. Runs the test job. +2. Builds cross-platform distribution artifacts. +3. Creates zip assets for the release. +4. Publishes a GitHub Release. +5. Publishes container images. +6. Publishes the AWS SAM application through the reusable SAM workflow. + +## Before Tagging + +Before creating the tag, make sure at least these items are done: + +* The branch contains the final code you want to release. +* [Whats-New.md](Whats-New.md) includes the user-facing release notes. +* Relevant user documentation such as [README.md](../README.md), [AWS-SAM.md](AWS-SAM.md), and [Configuration.md](Configuration.md) reflects the release. +* Local verification has been performed. + +Recommended checks: + +```bash +make go-fmt +make build +make test +``` + +## Tag Format + +Use semantic version tags in the form: + +```text +v.. +``` + +Examples: + +* `v0.44.1` +* `v0.45.0` +* `v1.0.0` + +## Create And Push The Tag + +Annotated tag example: ```bash -git tag -a v0.0.1 -m "testing the release process" -s -git push origin v0.0.1 +git tag -a v0.44.1 -m "release v0.44.1" +git push origin v0.44.1 ``` + +If your team requires signed tags, create the tag with `-s` instead of `-a`. + +## After Pushing + +After the tag is pushed, monitor these outcomes: + +* GitHub Release creation +* Distribution assets uploaded from `dist/assets` +* Container image publish job completion +* AWS SAM publish job completion + +If the release includes a public serverless update, verify the published application page in the AWS Serverless Application Repository after the workflow finishes. + +## Related Documentation + +* [Whats-New.md](Whats-New.md) +* [Development.md](Development.md) +* [AWS-SAM.md](AWS-SAM.md) diff --git a/docs/State-File-example.md b/docs/State-File-example.md index ca655df..4641145 100644 --- a/docs/State-File-example.md +++ b/docs/State-File-example.md @@ -1,37 +1,46 @@ -# State File example +# State File Example -This is an example of the `state file` the program will store in `AWS S3 Bucket`. +This document shows an example of the sync state file stored in S3. -As you see this use `JSON` serialization to save the data and the data is about: +The state file is an implementation detail used to make repeated synchronizations faster and to avoid unnecessary SCIM updates. It is useful for understanding how the project works, but it should not be treated as a stable external contract. -* Groups --> `groups` field -* Users --> `users` field -* Groups Members --> `groupsMembers` field +## What The State File Contains -Also the `State file` contains some `metadata`: +The JSON representation contains: -* schemaVersion --> this could change if the `fields` of the `state file` change -* codeVersion --> this inform you about the version of the code that generated the `state file` -* lastSync --> this is the date and time when the `state file` was generated +* `groups`: synchronized group data +* `users`: synchronized user data +* `groupsMembers`: group membership data used for reconciliation +* `schemaVersion`: state schema version +* `codeVersion`: application version that produced the state +* `lastSync`: timestamp of the last successful synchronization +* `hashCode`: top-level hash used to detect changes efficiently -and the `most important feature here` is the `hashCode` field, this is a `SHA256` hash of the each element of the `state file` content, and it is used to `save time in the operations` when we want to `detect changes`, also we can use that to checks `data integrity`. +The current schema version in the codebase is `1.0.0`. + +## Storage Location + +The exact object key depends on how you deploy the application: + +* The code default is `state.json` +* The AWS SAM template default is `data/state.json` + +In both cases, the object is stored in the configured S3 state bucket. + +## Example ```json { - "schemaVersion": "1.0.0", - "codeVersion": "v0.1.0", - "lastSync": "2023-10-21T18:48:49+02:00", - "hashCode": "e72d58ac523af315fa6f3ed3329b8a174f2938c9e67a573ed45217f4a1a7b4e2", "resources": { "groups": { "items": 1, "hashCode": "15cf5de941f6eb2d96e037675ac6f85401911889e12651f58990573c9f1f84ba", "resources": [ { - "ipid": "00xvir7l2tu59gn", + "ipid": "00examplegroup", "scimid": "b295b414-e091-70f6-3981-df556957e68a", - "name": "AWS-SSO-Administrators", - "email": "aws-sso-administrators@slashdevops.com", + "name": "AWS-Administrators", + "email": "aws-administrators@example.com", "hashCode": "bcc54ec742946488860ec5f11eac4c958a178393a837abc878749fc0c40fefea" } ] @@ -41,41 +50,41 @@ and the `most important feature here` is the `hashCode` field, this is a `SHA256 "hashCode": "bbbcf7f0ba3e94c811c03962ff986dcceffd97b1c95b0f6a50304df4d182380c", "resources": [ { - "hashCode": "4945a50f8b93337f5632dca20b49870f4507f0da28ee5d6d66add1f4b6df9045", - "ipid": "100439965050892133351", + "ipid": "100000000000000000001", "scimid": "2275b4a4-d031-70b1-1bb0-e5049d0a0689", - "userName": "christian.gonzalez@slashdevops.com", - "displayName": "Christian González Di Antonio", - "title": "Chief Technology Officer", + "userName": "alice@example.com", + "displayName": "Alice Example", + "title": "Platform Engineer", "userType": "admin#directory#user", - "preferredLanguage": "en-GB", + "preferredLanguage": "en-US", "emails": [ { - "value": "christian.gonzalez@slashdevops.com", + "value": "alice@example.com", "primary": true } ], "addresses": [ { - "formatted": "private address here", + "formatted": "123 Example Street" } ], "phoneNumbers": [ { - "value": "+55 555 555 555", + "value": "+1 555 0100", "type": "work" } ], "name": { - "formatted": "Christian González Di Antonio", - "familyName": "González Di Antonio", - "givenName": "Christian" + "formatted": "Alice Example", + "familyName": "Example", + "givenName": "Alice" }, "enterpriseData": { - "costCenter": "123654", - "department": "IT" + "costCenter": "ENG-001", + "department": "Engineering" }, - "active": true + "active": true, + "hashCode": "4945a50f8b93337f5632dca20b49870f4507f0da28ee5d6d66add1f4b6df9045" } ] }, @@ -87,17 +96,17 @@ and the `most important feature here` is the `hashCode` field, this is a `SHA256 "items": 1, "hashCode": "2b691179255bef46299eb3359433b5d019c6623904b90bf6fd032f4856ff7ded", "group": { - "ipid": "00xvir7l2tu59gn", + "ipid": "00examplegroup", "scimid": "b295b414-e091-70f6-3981-df556957e68a", - "name": "AWS-SSO-Administrators", - "email": "aws-sso-administrators@slashdevops.com", + "name": "AWS-Administrators", + "email": "aws-administrators@example.com", "hashCode": "bcc54ec742946488860ec5f11eac4c958a178393a837abc878749fc0c40fefea" }, "resources": [ { - "ipid": "100439965050892133351", + "ipid": "100000000000000000001", "scimid": "2275b4a4-d031-70b1-1bb0-e5049d0a0689", - "email": "christian.gonzalez@slashdevops.com", + "email": "alice@example.com", "status": "ACTIVE", "hashCode": "f78efeb7e034db070cf78c804174f8de32a6a823d80674bae4d012f0fbecaf1f" } @@ -105,6 +114,17 @@ and the `most important feature here` is the `hashCode` field, this is a `SHA256 } ] } - } + }, + "schemaVersion": "1.0.0", + "codeVersion": "v0.44.0", + "lastSync": "2026-04-03T10:15:00Z", + "hashCode": "e72d58ac523af315fa6f3ed3329b8a174f2938c9e67a573ed45217f4a1a7b4e2" } ``` + +## Related Documentation + +* [README.md](../README.md) +* [Configuration.md](Configuration.md) +* [AWS-SAM.md](AWS-SAM.md) +* [Demo.md](Demo.md) diff --git a/docs/Using-SSO.md b/docs/Using-SSO.md index 6ac9bc4..dc17dba 100644 --- a/docs/Using-SSO.md +++ b/docs/Using-SSO.md @@ -1,75 +1,104 @@ -# Using SSO +# Using AWS IAM Identity Center -**Warning:** Comments here are [IMHO](https://en.wiktionary.org/wiki/IMHO) +This document is a practical rollout guide for using `idp-scim-sync` with [AWS IAM Identity Center](https://aws.amazon.com/iam/identity-center/) and Google Workspace. -Start using [Single Sign-On (SSO)](https://en.wikipedia.org/wiki/Single_sign-on) in your AWS Accounts is hard to achieve, you must need to read a lot of documentation and of course, you need to know how to use the [AWS SSO service](https://aws.amazon.com/blogs/security/how-to-create-and-manage-users-within-aws-sso/). +It is intentionally opinionated in one area: stable group design matters more than short-term convenience. ->For me, __technical things__ are just things that are going to work sooner or later or as soon you understand how to use these. But __non-technical things__ are just things that most of the time you will improve according to __your time__ implementing __technical things__ and this could we call __"experience"__. +## Before You Deploy -So, said that, let me help you with my `"experience"` using SSO. +Before enabling automatic synchronization, make sure you have all of the following: -## Recommendations +* AWS IAM Identity Center enabled in the target AWS account or organization +* SCIM automatic provisioning enabled so you have a SCIM endpoint and access token +* A Google Workspace service account with domain-wide delegation +* Agreement on which Google Workspace groups should be synchronized -Before start +For the actual deployment mechanics, see [AWS-SAM.md](AWS-SAM.md). For command-level validation, see [idpscimcli.md](idpscimcli.md). -* Do a planning of `how many services` you will need to integrate with your `Identity Provider using SSO`, and `how many users and Groups you will need to create`. -* Use `Groups and their Members` to create `Users` in your SSO integration, `avoid the integration directly with Users`. -* Establish a `Naming Convention` for your `SSO Groups`. -* Use prefixes for your `SSO Groups name`. +## Recommended Operating Model -A little bit more +The project works best when you synchronize groups and let users be derived from those groups. -* Google Workspace Groups and AWS Single Sign-On are free of charge, so take advantage of this -* Filter the data in the `source` is always better than in the `process` -* [WYSIWYG](https://dictionary.cambridge.org/es/diccionario/ingles/wysiwyg) is better than `opaque or shadowed process`, I mean, if you have 1 group called `My Group` with `2 members`, `user.1@mydomain.com` and `user.2@mydomain.com` in the `Google Workspace`, everybody is expecting to see the same in `AWS SSO side` regardless of what this program does -* A process that scales independently of the `source` is better than a `process that needs too many changes during its escalation` +Recommended practices: -### Example +* Use groups and group membership as the source of truth +* Avoid managing individual users separately when group membership already defines access +* Keep the synchronized scope narrow with explicit Google Workspace group filters +* Establish naming conventions before the first production sync +* Prefer predictable group names over ad hoc per-team naming -Given Google Workspace Groups with these conditions: +## Why Group Naming Matters -| Group Name | Group Email | Members | -| ------------------ | ------------------------------ | ------------------------ | -| AWS Administrators | aws-administrator@mydomain.com | [a,b,c,d]@mydomain.com | -| AWS DevOps | aws-devops@mydomain.com | [f,g,h]@mydomain.com | -| AWS Developers | aws-developers@mydomain.com | [k,j,z,a,g]@mydomain.com | -| ... | ... | ... | +After the first successful sync, your AWS IAM Identity Center groups will typically receive permission set assignments. At that point, renaming groups becomes operationally expensive. -your [idpscim](https://github.com/slashdevops/idp-scim-sync/blob/main/docs/idpscim.md) `[AWS Lambda function|container image|cli]` could use `--gws-groups-filter 'name=AWS* email:aws-*'` +For this project, the most important stable identifiers are: -This is easy and it is in compliance with the previous recommendations, but I think the most important ones are: -> You can `increase or decrease` the number of `groups and their members` in __Google Workspace__ and never need to `change the parameters` of the __idpscim__ `[AWS Lambda function|container image|cli]` +| Entity | Attribute you should keep stable | +| --- | --- | +| Groups | Display name | +| Users | Email address | -## TL;DR +If a group name changes in the identity provider, AWS IAM Identity Center can no longer match it to the previous synchronized object in the way you expect for access governance. That can translate into lost permission set associations and manual cleanup. -__NOTES:__ +The safest rule is simple: -* This is a `WIP`, keep calm and don't panic -* [TL;DR means: Too Long Didn't Read](https://en.wikipedia.org/wiki/TL;DR) +* Finalize your group naming convention before the first production sync -### Planning +## Start With A Filter Strategy -### Groups and members +Filtering at the source is usually safer than synchronizing everything and trying to narrow the result later. -### Use Naming Conventions +Example approach: -The most important part of implementing SSO is the planning of the things you need to do before that, but for me the most important one is `Groups name and Naming convention`, +| Group Name | Group Email | +| --- | --- | +| AWS Administrators | `aws-administrators@example.com` | +| AWS DevOps | `aws-devops@example.com` | +| AWS Developers | `aws-developers@example.com` | -__Why?__ +With a naming pattern like that, `idpscim` can use filters such as: -Because one you `sync the groups and users` the first time with [AWS SSO](https://aws.amazon.com/single-sign-on) and assign to them the [Permission sets](https://docs.aws.amazon.com/singlesignon/latest/userguide/permissionsetsconcept.html) you should not change the `Groups and Users main attributes`, with in case of this program are: +```bash +--gws-groups-filter 'name:AWS*' +``` -| Entity | Main Attribute | -| ------ | -------------- | -| Groups | Name | -| Users | Email | +That gives you a stable boundary for future growth. You can add or remove members and even create new `AWS...` groups without needing to rework the deployment parameters every time. -Of course, you can change the `Groups and Users main attributes` but after that you will lose the `Permission sets` assigned to them, so __you should not change these__. +## Rollout Sequence -__Again, Why?__ +Recommended rollout order: ->Imagine you have __40 Groups__ and __1,000 Users__ and some of these __Groups__ has __50 Users__ and you have assigned some [Permission sets](https://docs.aws.amazon.com/singlesignon/latest/userguide/permissionsetsconcept.html) to this `Group`, so if you __change the Name__ of __this Group__ in your Identity Provider, our case __Google Workspace Directory Service__, __50 users of your company will be lost their permissions__ to your __AWS Accounts in just one moment__, and this could be __hard to fix__ is you don't have implemented any [IaC](https://en.wikipedia.org/wiki/Infrastructure_as_code) practice to match the __Groups__ and __Users__ with the __Permission sets__ assigned to them. +1. Plan the target group naming convention. +2. Create or clean up the Google Workspace groups you want to synchronize. +3. Validate filters and credentials with `idpscimcli`. +4. Deploy the application in a non-production AWS account first. +5. Verify synchronized groups, users, and permission assignments. +6. Move to production once the naming and filter strategy is stable. -So, to avoid this scenario you should: __Plan your Groups Naming Convention First__ +## Validation Commands -### Use Name Prefixes +Before enabling scheduled synchronization, run explicit validation commands. + +Check Google Workspace groups: + +```bash +./build/idpscimcli gws groups list \ + --gws-service-account-file credentials.json \ + --gws-user-email admin@example.com \ + --gws-groups-filter 'name=AWS*' +``` + +Check AWS IAM Identity Center SCIM connectivity: + +```bash +./build/idpscimcli aws service config \ + --aws-scim-endpoint https://example.awsapps.com/scim/v2/ \ + --aws-scim-access-token "$SCIM_ACCESS_TOKEN" +``` + +## Related Documentation + +* [Configuration.md](Configuration.md) +* [AWS-SAM.md](AWS-SAM.md) +* [idpscim.md](idpscim.md) +* [idpscimcli.md](idpscimcli.md) diff --git a/docs/Whats-New.md b/docs/Whats-New.md index f57ba23..471bd15 100644 --- a/docs/Whats-New.md +++ b/docs/Whats-New.md @@ -2,6 +2,14 @@ This document tracks notable changes, new features, and bug fixes across releases. +## Unreleased + +### Documentation Refresh + +Refreshed the project documentation to align it with the current Go, AWS SAM, and AWS Serverless Application Repository workflows. + +This update expands the README documentation map, clarifies how to deploy and update the serverless application, documents the two binaries built from `cmd/`, and modernizes the remaining docs in the `docs/` folder so they are linked and project-valid. + ## v0.40.1 ### Improved HTTP Retry Library diff --git a/docs/idpscim.md b/docs/idpscim.md index 2f1854b..61dbdd0 100644 --- a/docs/idpscim.md +++ b/docs/idpscim.md @@ -1,68 +1,125 @@ # idpscim -This is in charge of keeping Google Workspace Groups and Users sync with AWS Single Sign-On service using SCIM protocol, to do that in an efficient way it stores the last sync data into an `AWS S3 Bucket` and periodically it will check if there are changes. +`idpscim` is the main synchronization program in this repository. It reads Google Workspace groups and members, compares them with AWS IAM Identity Center through the SCIM API, and stores synchronization state in S3 so later runs can avoid unnecessary updates. -This program could work in three ways: +This is the program executed by the deployed Lambda function. -1. As an [AWS Lambda function](https://aws.amazon.com/lambda/?nc1=h_ls) deployed via [AWS SAM](https://aws.amazon.com/serverless/sam/) or consumed directly from the [AWS Serverless Application Repository](https://aws.amazon.com/serverless/serverlessrepo/?nc1=h_ls) -2. As a command line tool -3. As a Docker container +## Source And Build Output -To understand how to configure the program, please read the [Configuration](Configuration.md) file. +| Item | Location | +| --- | --- | +| Source entry point | [cmd/idpscim/main.go](../cmd/idpscim/main.go) | +| Local binary | `build/idpscim` | +| Lambda build artifact | `.aws-sam/build/LambdaFunction/bootstrap` | -## idpscim --help +## Supported Run Modes + +`idpscim` can run in three ways: + +1. As an AWS Lambda function deployed with AWS SAM or consumed from the AWS Serverless Application Repository. +2. As a local command-line program. +3. As a container image. + +For the full configuration model, see [Configuration.md](Configuration.md). + +## Key Flags + +The current `idpscim --help` surface is summarized below. + +### General And Logging + +| Flag | Purpose | +| --- | --- | +| `--config-file`, `-c` | Path to the configuration file | +| `--debug`, `-d` | Shortcut to force debug logging | +| `--log-format`, `-f` | Log output format | +| `--log-level`, `-l` | Log verbosity | +| `--version`, `-v` | Show version information | + +### Google Workspace Input + +| Flag | Purpose | +| --- | --- | +| `--gws-service-account-file`, `-s` | Path to the Google Workspace service account JSON | +| `--gws-user-email`, `-u` | Delegated Google Workspace user email | +| `--gws-groups-filter`, `-q` | One or more filters that restrict which groups are synchronized | +| `--gws-service-account-file-secret-name`, `-o` | Secret name used when resolving the service account JSON from AWS Secrets Manager | +| `--gws-user-email-secret-name`, `-p` | Secret name used when resolving the delegated user email from AWS Secrets Manager | + +### AWS SCIM And State Storage + +| Flag | Purpose | +| --- | --- | +| `--aws-scim-endpoint`, `-e` | AWS IAM Identity Center SCIM endpoint | +| `--aws-scim-access-token`, `-t` | AWS IAM Identity Center SCIM access token | +| `--aws-scim-endpoint-secret-name`, `-n` | Secret name used when resolving the SCIM endpoint from AWS Secrets Manager | +| `--aws-scim-access-token-secret-name`, `-j` | Secret name used when resolving the SCIM token from AWS Secrets Manager | +| `--aws-s3-bucket-name`, `-b` | S3 bucket used to store the sync state | +| `--aws-s3-bucket-key`, `-k` | S3 object key used for the sync state | +| `--use-secrets-manager`, `-g` | Tell the program to load values from AWS Secrets Manager | + +### Sync Behavior + +| Flag | Purpose | +| --- | --- | +| `--sync-method`, `-m` | Sync strategy. The implemented value is `groups` | +| `--sync-user-fields` | Optional user fields to synchronize | + +## Example Local Run + +Build the binary: ```bash -./build/idpscim --help - -Sync your Google Workspace Groups and Users to AWS Single Sign-On using -AWS SSO SCIM API (https://docs.aws.amazon.com/singlesignon/latest/developerguide/what-is-scim.html). - -Usage: - idpscim [flags] - -Flags: - -k, --aws-s3-bucket-key string AWS S3 Bucket key to store the state (default "state.json") - -b, --aws-s3-bucket-name string AWS S3 Bucket name to store the state - -t, --aws-scim-access-token string AWS SSO SCIM API Access Token - -j, --aws-scim-access-token-secret-name string AWS Secrets Manager secret name for AWS SSO SCIM API Access Token (default "IDPSCIM_SCIMAccessToken") - -e, --aws-scim-endpoint string AWS SSO SCIM API Endpoint - -n, --aws-scim-endpoint-secret-name string AWS Secrets Manager secret name for AWS SSO SCIM API Endpoint (default "IDPSCIM_SCIMEndpoint") - -c, --config-file string configuration file (default ".idpscim.yaml") - -d, --debug fast way to set the log-level to debug - -q, --gws-groups-filter strings GWS Groups query parameter, example: --gws-groups-filter 'name:Admin* email:admin*' --gws-groups-filter 'name:Power* email:power*' - -s, --gws-service-account-file string Google Workspace service account file (default "credentials.json") - -o, --gws-service-account-file-secret-name string AWS Secrets Manager secret name for Google Workspace service account file (default "IDPSCIM_GWSServiceAccountFile") - -u, --gws-user-email string GWS user email with allowed access to the Google Workspace Service Account - -p, --gws-user-email-secret-name string AWS Secrets Manager secret name for GWS user email with allowed access to the Google Workspace Service Account (default "IDPSCIM_GWSUserEmail") - -h, --help help for idpscim - -f, --log-format string set the log format (default "text") - -l, --log-level string set the log level [panic|fatal|error|warn|info|debug|trace] (default "info") - -m, --sync-method string Sync method to use [groups] (default "groups") - --sync-user-fields strings optional user fields to sync (e.g., phoneNumbers,addresses,enterpriseData); default: all fields - -g, --use-secrets-manager use AWS Secrets Manager content or not - -v, --version version for idpscim +make build ``` -## Using the AWS Lambda function +Run the program with direct credentials and a state bucket: -This could be deployed using the [official AWS Serverless public repository]() or using the method explained in the [AWS SAM](docs/AWS-SAM.md) section. +```bash +./build/idpscim \ + --gws-service-account-file credentials.json \ + --gws-user-email admin@example.com \ + --gws-groups-filter 'name:AWS*' \ + --aws-scim-endpoint https://example.awsapps.com/scim/v2/ \ + --aws-scim-access-token "$SCIM_ACCESS_TOKEN" \ + --aws-s3-bucket-name idp-scim-sync-state-123456789012-us-east-1 \ + --aws-s3-bucket-key data/state.json \ + --sync-method groups \ + --sync-user-fields phoneNumbers,addresses,enterpriseData +``` -## Using the command line tool +If you prefer to resolve secrets at runtime, provide the secret names and add `--use-secrets-manager`. -This could be used following the instructions in the main [README.md](docs/README.md) file. +## Deploy As Lambda -## Using the container image +You can deploy the Lambda version in either of these ways: -Build and test the container image locally (requires [podman](https://podman.io/)): +* Public application page: [AWS Serverless Application Repository](https://serverlessrepo.aws.amazon.com/applications/us-east-1/889836709304/idp-scim-sync) +* From source using the workflow described in [AWS-SAM.md](AWS-SAM.md) + +For most users, the public AWS Serverless Application Repository page is the simplest option. For contributors and private deployments, use the source-based SAM workflow. + +## Run As A Container + +Build the image locally: ```bash make build-dist GIT_VERSION=test make container-build ``` -Execute: +Run the container: ```bash -podman run -it -v $HOME/tmp/idpscim.yaml:/app/.idpscim.yaml ghcr.io/slashdevops/idp-scim-sync:latest idpscim --debug +podman run --rm -it \ + -v "$PWD/.idpscim.yaml:/app/.idpscim.yaml:ro" \ + ghcr.io/slashdevops/idp-scim-sync:latest \ + idpscim --config-file .idpscim.yaml ``` + +## Related Documentation + +* [Configuration.md](Configuration.md) +* [AWS-SAM.md](AWS-SAM.md) +* [Development.md](Development.md) +* [README.md](../README.md) diff --git a/docs/idpscimcli.md b/docs/idpscimcli.md index 7941d58..37e735b 100644 --- a/docs/idpscimcli.md +++ b/docs/idpscimcli.md @@ -1,106 +1,198 @@ # idpscimcli -This is a `command-line tool` to check and validate some functionalities implemented in idpscim. +`idpscimcli` is the helper command-line program used to validate and inspect the same systems that `idpscim` synchronizes. -The idea of this tool is to check the configuration you will implement in the [idpscim](idpscim.md) program, like the `filter` used for `Google Workspace Groups` and `Users` and the inventory of users and groups in both sides. +Use it when you want to answer questions such as: -## idpscimcli --help +- Can I reach the AWS IAM Identity Center SCIM endpoint? +- Which groups or users currently exist in AWS SCIM? +- Which Google Workspace groups match my filters? +- Which members are inside those groups? + +## Source And Build Output + +| Item | Location | +| --- | --- | +| Source entry point | [cmd/idpscimcli/main.go](../cmd/idpscimcli/main.go) | +| Local binary | `build/idpscimcli` | + +## Command Tree + +The current command surface is: + +```text +idpscimcli +|- aws +| |- service config +| |- groups list +| `- users list +`- gws + |- groups list + |- groups members list + `- users list +``` + +## Root Flags + +These flags apply to the whole CLI: + +| Flag | Purpose | +| --- | --- | +| `--config-file`, `-c` | Path to the configuration file | +| `--debug`, `-d` | Enable debug logging | +| `--log-format`, `-f` | Log output format | +| `--log-level`, `-l` | Log verbosity | +| `--output-format` | Output format: `json` or `yaml` | +| `--timeout` | Request timeout for API calls | +| `--version`, `-v` | Show version information | + +## AWS Commands + +Use the `aws` command group to inspect the AWS IAM Identity Center SCIM API. + +### Shared AWS Flags + +| Flag | Purpose | +| --- | --- | +| `--aws-scim-endpoint`, `-e` | AWS IAM Identity Center SCIM endpoint | +| `--aws-scim-access-token`, `-t` | AWS IAM Identity Center SCIM access token | + +### Available AWS Subcommands + +| Command | Purpose | +| --- | --- | +| `idpscimcli aws service config` | Show SCIM service provider configuration | +| `idpscimcli aws groups list` | List groups from the AWS SCIM API | +| `idpscimcli aws users list` | List users from the AWS SCIM API | + +### AWS Examples + +Show SCIM service configuration: ```bash -./idpscimcli --help - -This is a Command-Line Interfaced (CLI) to help you validate and check your source and target Single Sign-On endpoints. -Check your AWS Single Sign-On (SSO) / Google Workspace Groups users and groups and validate your filters over Google Workspace users and groups. - -Usage: - idpscimcli [command] - -Available Commands: - aws AWS SSO SCIM commands - completion Generate the autocompletion script for the specified shell - gws Google Workspace commands - help Help about any command - -Flags: - -c, --config-file string configuration file (default ".idpscim.yaml") - -d, --debug enable log debug level - -h, --help help for idpscimcli - -f, --log-format string set the log format (default "text") - -l, --log-level string set the log level (default "info") - --output-format string output format (json|yaml) (default "json") - --timeout duration requests timeout (default 10s) - -v, --version version for idpscimcli - -Use "idpscimcli [command] --help" for more information about a command. +./build/idpscimcli aws service config \ + --aws-scim-endpoint https://example.awsapps.com/scim/v2/ \ + --aws-scim-access-token "$SCIM_ACCESS_TOKEN" ``` -## Example of usage +List groups with a SCIM filter: ```bash -./idpscimcli gws groups list \ - --gws-service-account-file credentials.json \ - --gws-user-email my-service-account-user@my-company-email.com \ - --gws-groups-filter "name='My Team - Support'" \ - --gws-groups-filter "name='My Tool' email=my-tool@my-company-email.com" \ - --gws-groups-filter 'email=other-group' \ - --gws-groups-filter 'email="this is other group name"' +./build/idpscimcli aws groups list \ + --aws-scim-endpoint https://example.awsapps.com/scim/v2/ \ + --aws-scim-access-token "$SCIM_ACCESS_TOKEN" \ + --filter 'displayName eq "Engineering"' +``` + +List users: + +```bash +./build/idpscimcli aws users list \ + --aws-scim-endpoint https://example.awsapps.com/scim/v2/ \ + --aws-scim-access-token "$SCIM_ACCESS_TOKEN" ``` -## Building the project +## Google Workspace Commands -To build the project locally, you will need to have installed and configured at least the following: +Use the `gws` command group to inspect Google Workspace objects with the same credentials model used by the main sync program. -1. [git](https://git-scm.com/) -2. [Go](https://go.dev/learn/) -3. [make](https://www.gnu.org/software/make/) +### Shared Google Workspace Flags -Then you will need to clone the repository in your local machine, and execute the following commands: +| Flag | Purpose | +| --- | --- | +| `--gws-service-account-file`, `-s` | Path to the Google Workspace service account JSON | +| `--gws-user-email`, `-u` | Delegated Google Workspace user email | -* Compile for your Operating System: +### Available Google Workspace Subcommands + +| Command | Purpose | +| --- | --- | +| `idpscimcli gws groups list` | List groups that match the provided group filters | +| `idpscimcli gws groups members list` | List the members of the groups that match the filters | +| `idpscimcli gws users list` | List users that match the provided user filters | + +### Google Workspace Filter Flags + +| Command | Flag | +| --- | --- | +| `gws groups list` | `--gws-groups-filter`, `-q` | +| `gws groups members list` | `--gws-groups-filter`, `-q` | +| `gws users list` | `--gws-users-filter`, `-r` | + +### Google Workspace Examples + +List groups: ```bash -make +./build/idpscimcli gws groups list \ + --gws-service-account-file credentials.json \ + --gws-user-email admin@example.com \ + --gws-groups-filter 'name=AWS*' ``` -then the binaries are in `build/` folder. - -* `Cross-compiling` the project for `Windows`, `MacOS` and `Linux` (default) +List members of matching groups: ```bash -make clean -make test # optional -make build-dist +./build/idpscimcli gws groups members list \ + --gws-service-account-file credentials.json \ + --gws-user-email admin@example.com \ + --gws-groups-filter 'email=aws-admins@example.com' ``` -then the binaries are in `dist/` folder. +List users: -* Others Operating Systems, see the list of supported platforms in the [syslist.go](https://github.com/golang/go/blob/master/src/go/build/syslist.go) +```bash +./build/idpscimcli gws users list \ + --gws-service-account-file credentials.json \ + --gws-user-email admin@example.com \ + --gws-users-filter 'email=alice@example.com' +``` + +Return YAML instead of JSON: ```bash -make clean -GO_OS= GO_ARCH= make test # optional -GO_OS= GO_ARCH= make build-dist +./build/idpscimcli gws groups list \ + --gws-service-account-file credentials.json \ + --gws-user-email admin@example.com \ + --gws-groups-filter 'name=AWS*' \ + --output-format yaml ``` -then the binaries are in `dist/` folder. +## Build And Run + +Build the binary locally: + +```bash +make build +./build/idpscimcli --help +``` -* Execute +Cross-compile for distribution: ```bash -./idpscimcli --help +make build-dist ``` -## Using the container image +## Run From The Container Image -Build and test the container image locally (requires [podman](https://podman.io/)): +Build the image locally: ```bash make build-dist GIT_VERSION=test make container-build ``` -Execute: +Run the CLI from the image: ```bash -podman run -it -v $HOME/tmp/idpscim.yaml:/app/.idpscim.yaml ghcr.io/slashdevops/idp-scim-sync:latest idpscimcli --debug +podman run --rm -it \ + -v "$PWD/.idpscim.yaml:/app/.idpscim.yaml:ro" \ + ghcr.io/slashdevops/idp-scim-sync:latest \ + idpscimcli --config-file .idpscim.yaml ``` + +## Related Documentation + +- [idpscim.md](idpscim.md) +- [Configuration.md](Configuration.md) +- [Development.md](Development.md) From c941a5c68a4928afea25f18623ad617dc5f07a97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Gonz=C3=A1lez=20Di=20Antonio?= Date: Fri, 3 Apr 2026 12:24:53 +0200 Subject: [PATCH 7/7] chore: add new words --- .vscode/settings.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.vscode/settings.json b/.vscode/settings.json index dc83994..75b5c62 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,6 +4,8 @@ "amzn", "awsconf", "AWSCURRENT", + "AWSGWS", + "awslabs", "AWSS", "AWSSCIM", "Babs", @@ -46,6 +48,7 @@ "hashcode", "hashicorp", "httpretrier", + "httpx", "idpid", "idpscim", "idpscimcli", @@ -77,6 +80,7 @@ "sirupsen", "slashdevops", "softprops", + "ssosync", "stackset", "stretchr", "stscreds",