Post

Automatic Provisioning of AWS IAM Identity Center Users and Groups from Google Workspace Directory using SSO Sync

Introduction

AWS IAM Identity Center supports automatic provisioning from various providers, including OneLogin, Microsoft Azure Active Directory, on-premise MS Active Directory, and other supported identity providers via the System for Cross-domain Identity Management (SCIM) implementation.

Google Workspace custom Security Assertion Markup Language (SAML) applications, on the other hand, don’t support automatic provisioning yet. On the other hand, AWS and Google are working with Fast Federation (FastFed) Working Group to make this feature available.

In the meantime, to automate the process of synchronizing users and groups from the Google Workspace Directory to the AWS IAM Identity Center, we will use the SSOSYNC project provided by AWSLABS.

In this post, we will walk you through the process of how the synchronization works and set up of SSOSYNC, running it locally for testing/debugging and deploying it as a serverless application.

Identity Synchronization Diagram

Identity Synchronization Diagram Identity Synchronization Diagram

Created with mermaid.js

Google GCP, Google Workspace, and AWS IAM IC Setup

We will set up the Google GCP Service Account, Google Workspace for Domain wide delegation, and AWS IAM Identity Center SCIM Credentials as required settings and parameters for our SSO Sync.

Google GCP

First create an isolated GCP project only for AWS IAM Identity Center purpose. Then create or Enable the API Services for Admin SDK API.

Create a Project

Create a Project Create a Project

Enable API and Services

Enable API and Services Enable API and Services

Admin SDK API

Admin SDK API Admin SDK API

Enable Admin SDK API

Enable Admin SDK API Enable Admin SDK API

Service Account and Client ID

Create a Service Account this serves as our credentials to access the Google Workspace Directory resources.

Select Service Account Credential

Service Account Credential Service Account Credential

Provide Service Account Credential Details

Service Account Credential Details Service Account Credential Details

Select Service Account Create New Key

Service Account Create New Key Service Account Create New Key

Service Account Create JSON Type Private Key

A JSON file will automatically be downloaded by the browser with a filename format named aws-iam-identity-center-xxxxxx-xxxxxxxxxxxx.json. Save it in a safe place for our SSO Sync CLI tool and for serverless application to log into Google.

Service Account Create JSON Type Private Key Service Account Create JSON Type Private Key

To identify and used it easily, just rename the file aws-iam-identity-center-xxxxxx-xxxxxxxxxxxx.json to credentials.json

1
mv aws-iam-identity-center-xxxxxx-xxxxxxxxxxxx.json credentials.json

Service Account Credential Client ID

Copy the 21 digit Unique ID this will be our Client ID for Google Workspace Domain Wide Delegation

Service Account Credential Client ID Service Account Credential Client ID

Google Workspace Domain Wide Delegation

Domain wide delegation settings provides a linkage from our service account to access the Google Workspace Directory based on the scopes we set, for what only the SSO Sync able to obtain.

Manage Domain Wide Delegation

Manage Domain wide delegation Manage Domain wide delegation

Domain Wide Delegation Add Client

Add the Client ID we copied from the Service Account details form IAM and Admin (GCP) and add the list of OAuth Scopes.

1
2
3
https://www.googleapis.com/auth/admin.directory.group.readonly
https://www.googleapis.com/auth/admin.directory.group.member.readonly
https://www.googleapis.com/auth/admin.directory.user.readonly

Domain wide delegation Add Client Domain wide delegation Add Client

AWS IAM Identity Center Automatic provisioning

On AWS IAM Identity Center enable the automatic provisioning to complete the coordination from Google Workspace Directory

Please take note of the SCIM credentials right after we enable them.

Enable Automatic provisioning

Enable Automatic provisioning Enable Automatic provisioning

Automatic provisioning SCIM Configuration

Copy the details from the SCIM endpoint to the SSOSYNC_SCIM_ENDPOINT.txt file and the Access token to the SSOSYNC_SCIM_ACCESS_TOKEN.txt file.

Save these in a safe place for our SSO Sync CLI tool and for serverless application.

Automatic provisioning SCIM Configuration Automatic provisioning SCIM Configuration

Setup the SSO Sync (from AWS Labs)

Clone and Build the SSO Sync from the Source Repository

AWS Labs provided the tool to complete the process, and it serves as a pipeline for users and groups from Google Workspace Directory to AWS IAM Identity Center. The project source requires building, and a compiled distributed binary is created.

Clone SSO Sync Repository

Copy the source from the AWS Github repository.

1
2
3
git clone https://github.com/awslabs/ssosync.git
cd ssosync
code .

Build the SSO Sync

Make sure you have the GO installed in your system.

If you are on macOS and want to test the applications, use this command line option to build the specific binary for macOS

1
2
GOOS=darwin GOARCH=amd64 make go-build
GOOS=darwin GOARCH=arm64 make go-build

For Linux and serverless applications, use this command line option.

1
GOOS=linux GOARCH=amd64 make go-build

Once a build is successfully run, a binary file ./ssosync is created.

Manually Sync through CLI (Testing or Debugging)

Using environment variables, we have provided the least required parameter for our SSO Sync.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
SSOSYNC_LOG_LEVEL=debug
SSOSYNC_LOG_FORMAT=text
SSOSYNC_GOOGLE_CREDENTIALS=credentials.json
SSOSYNC_GOOGLE_ADMIN=johndoe@domain.tld
SSOSYNC_SCIM_ENDPOINT=`cat SSOSYNC_SCIM_ENDPOINT.txt`
SSOSYNC_SCIM_ACCESS_TOKEN=`cat SSOSYNC_SCIM_ACCESS_TOKEN.txt`
SSOSYNC_REGION=us-east-1
SSOSYNC_IDENTITY_STORE_ID=d-xxxxxxxxxx
SSOSYNC_USER_MATCH=
SSOSYNC_GROUP_MATCH=
SSOSYNC_SYNC_METHOD=groups
SSOSYNC_IGNORE_GROUPS=
SSOSYNC_IGNORE_USERS=
SSOSYNC_INCLUDE_GROUPS=

AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=

Load the environment variables on your shell session.

1
2
$ set -a && source .env && set +a

Run the SSO Sync binary

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$ ./ssosync

# INFO[0000] Syncing AWS users and groups from Google Workspace SAML Application
# INFO[0000] syncing                                       sync_method=groups
# INFO[0000] get google groups                             query=
# DEBU[0001] preparing list of google users and then google groups and their members
# DEBU[0001] get group members from google                 group=administrator
# DEBU[0001] get users                                     group=administrator
# DEBU[0001] get user                                      group=administrator id=johndoe@domain.tld
# INFO[0002] get existing aws groups
# INFO[0003] get existing aws users
# INFO[0003] get active status for aws users
# INFO[0004] preparing map of user id's to user
# DEBU[0004] preparing list of aws groups and their members
# INFO[0004] syncing changes
# DEBU[0004] deleting aws users deleted in google
# DEBU[0004] updating aws users updated in google
# DEBU[0004] creating aws users added in google
# DEBU[0004] creating aws groups added in google
# DEBU[0004] validating groups members, equals in aws and google
# DEBU[0004] finding user                                  group=administrator user=johndoe@domain.tld
# DEBU[0005] checking user is in group already             group=administrator user=johndoe@domain.tld
# DEBU[0005] delete aws groups deleted in google
# INFO[0005] sync completed

:tada: As you have seen, the SSO Sync STDOUT shows the expected results. Users and Groups from Google Workspace Directory sync perfectly to our AWS IAM Identity Center.

Periodically Sync through AWS SAM (Production)

Build the SAM to deployable template

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ sam build

# Building codeuri: /path/to/awslabs/ssosync runtime: go1.x metadata: {} architecture: x86_64 functions: SSOSyncFunction
# Running GoModulesBuilder:Build

# Build Succeeded

# Built Artifacts  : .aws-sam/build
# Built Template   : .aws-sam/build/template.yaml

# Commands you can use next
# =========================
# [*] Validate SAM template: sam validate
# [*] Invoke Function: sam local invoke
# [*] Test Function in the Cloud: sam sync --stack-name  --watch
# [*] Deploy: sam deploy --guided

Deploy the SSO Sync SAM Application

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
$ sam deploy --guided

# Configuring SAM deploy
# ======================

#   Looking for config file [samconfig.toml] :  Not found

#   Setting default arguments for 'sam deploy'
#   =========================================
#   Stack Name [sam-app]: SSOSync
#   AWS Region [us-east-1]:
#   Parameter ScheduleExpression [rate(15 minutes)]:
#   Parameter LogLevel [warn]:
#   Parameter LogFormat [json]:
#   Parameter GoogleCredentials:
#   Parameter GoogleAdminEmail:
#   Parameter SCIMEndpointUrl:
#   Parameter SCIMEndpointAccessToken:
#   Parameter Region:
#   Parameter IdentityStoreID:
#   Parameter GoogleUserMatch []:
#   Parameter GoogleGroupMatch []:
#   Parameter IgnoreGroups []:
#   Parameter IgnoreUsers []:
#   Parameter IncludeGroups []:
#   Parameter SyncMethod [groups]:
#   #Shows you resources changes to be deployed and require a 'Y' to initiate deploy
#   Confirm changes before deploy [y/N]:
#   #SAM needs permission to be able to create roles to connect to the resources in your template
#   Allow SAM CLI IAM role creation [Y/n]:
#   #Preserves the state of previously provisioned resources when an operation fails
#   Disable rollback [y/N]:
#   Save arguments to configuration file [Y/n]:
#   SAM configuration file [samconfig.toml]:
#   SAM configuration environment [default]:

#   **** TRUNCATED DETAILS ****

#   Deploying with following values
#   ===============================
#   Stack name                   : SSOSync
#   Region                       : us-east-1
#   Confirm changeset            : False
#   Disable rollback             : False
#   Deployment s3 bucket         : aws-sam-cli-managed-default-samclisourcebucket-*************
#   Capabilities                 : ["CAPABILITY_IAM"]
#   Parameter overrides          : {"ScheduleExpression": "rate(15 minutes)", "LogLevel": "warn", "LogFormat": "json", "GoogleCredentials": "*****", "GoogleAdminEmail": "*****", "SCIMEndpointUrl": "*****", "SCIMEndpointAccessToken": "*****", "Region": "*****", "IdentityStoreID": "*****", "GoogleUserMatch": "", "GoogleGroupMatch": "", "IgnoreGroups": "", "IgnoreUsers": "", "IncludeGroups": "", "SyncMethod": "groups"}
#   Signing Profiles             : {}

# Initiating deployment
# =====================
# File with same data already exists at SSOSync/*************.template, skipping upload

# Waiting for changeset to be created..
# CloudFormation stack changeset
# -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
# Operation                                         LogicalResourceId                                 ResourceType                                      Replacement
# -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
# + Add                                             AWSGoogleAdminEmail                               AWS::SecretsManager::Secret                       N/A
# + Add                                             AWSGoogleCredentialsSecret                        AWS::SecretsManager::Secret                       N/A
# + Add                                             AWSIdentityStoreIDSecret                          AWS::SecretsManager::Secret                       N/A
# + Add                                             AWSRegionSecret                                   AWS::SecretsManager::Secret                       N/A
# + Add                                             AWSSCIMAccessTokenSecret                          AWS::SecretsManager::Secret                       N/A
# + Add                                             AWSSCIMEndpointSecret                             AWS::SecretsManager::Secret                       N/A
# + Add                                             SSOSyncFunctionRole                               AWS::IAM::Role                                    N/A
# + Add                                             SSOSyncFunctionSyncScheduledEventPermission       AWS::Lambda::Permission                           N/A
# + Add                                             SSOSyncFunctionSyncScheduledEvent                 AWS::Events::Rule                                 N/A
# + Add                                             SSOSyncFunction                                   AWS::Lambda::Function                             N/A
# -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

# Changeset created successfully. arn:aws:cloudformation:us-east-1:*************:changeSet/samcli-deploy*************/*************


# 2023-02-13 00:52:57 - Waiting for stack create/update to complete

# CloudFormation events from stack operations (refresh every 0.5 seconds)
# -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
# ResourceStatus                                    ResourceType                                      LogicalResourceId                                 ResourceStatusReason
# -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
# CREATE_IN_PROGRESS                                AWS::SecretsManager::Secret                       AWSSCIMEndpointSecret                             -
# CREATE_IN_PROGRESS                                AWS::SecretsManager::Secret                       AWSSCIMAccessTokenSecret                          -
# CREATE_IN_PROGRESS                                AWS::SecretsManager::Secret                       AWSGoogleCredentialsSecret                        -
# CREATE_IN_PROGRESS                                AWS::SecretsManager::Secret                       AWSRegionSecret                                   -
# CREATE_IN_PROGRESS                                AWS::SecretsManager::Secret                       AWSIdentityStoreIDSecret                          -
# CREATE_IN_PROGRESS                                AWS::SecretsManager::Secret                       AWSSCIMEndpointSecret                             Resource creation Initiated
# CREATE_IN_PROGRESS                                AWS::SecretsManager::Secret                       AWSRegionSecret                                   Resource creation Initiated
# CREATE_IN_PROGRESS                                AWS::SecretsManager::Secret                       AWSSCIMAccessTokenSecret                          Resource creation Initiated
# CREATE_COMPLETE                                   AWS::SecretsManager::Secret                       AWSSCIMEndpointSecret                             -
# CREATE_IN_PROGRESS                                AWS::SecretsManager::Secret                       AWSIdentityStoreIDSecret                          Resource creation Initiated
# CREATE_COMPLETE                                   AWS::SecretsManager::Secret                       AWSSCIMAccessTokenSecret                          -
# CREATE_IN_PROGRESS                                AWS::SecretsManager::Secret                       AWSGoogleAdminEmail                               Resource creation Initiated
# CREATE_COMPLETE                                   AWS::SecretsManager::Secret                       AWSRegionSecret                                   -
# CREATE_COMPLETE                                   AWS::SecretsManager::Secret                       AWSIdentityStoreIDSecret                          -
# CREATE_COMPLETE                                   AWS::SecretsManager::Secret                       AWSGoogleCredentialsSecret                        -
# CREATE_COMPLETE                                   AWS::SecretsManager::Secret                       AWSGoogleAdminEmail                               -
# CREATE_IN_PROGRESS                                AWS::IAM::Role                                    SSOSyncFunctionRole                               -
# CREATE_IN_PROGRESS                                AWS::IAM::Role                                    SSOSyncFunctionRole                               Resource creation Initiated
# CREATE_COMPLETE                                   AWS::IAM::Role                                    SSOSyncFunctionRole                               -
# CREATE_IN_PROGRESS                                AWS::Lambda::Function                             SSOSyncFunction                                   -
# CREATE_IN_PROGRESS                                AWS::Lambda::Function                             SSOSyncFunction                                   Resource creation Initiated
# CREATE_COMPLETE                                   AWS::Lambda::Function                             SSOSyncFunction                                   -
# CREATE_IN_PROGRESS                                AWS::Events::Rule                                 SSOSyncFunctionSyncScheduledEvent                 -
# CREATE_IN_PROGRESS                                AWS::Events::Rule                                 SSOSyncFunctionSyncScheduledEvent                 Resource creation Initiated
# CREATE_COMPLETE                                   AWS::Events::Rule                                 SSOSyncFunctionSyncScheduledEvent                 -
# CREATE_IN_PROGRESS                                AWS::Lambda::Permission                           SSOSyncFunctionSyncScheduledEventPermission       -
# CREATE_IN_PROGRESS                                AWS::Lambda::Permission                           SSOSyncFunctionSyncScheduledEventPermission       Resource creation Initiated
# CREATE_COMPLETE                                   AWS::Lambda::Permission                           SSOSyncFunctionSyncScheduledEventPermission       -
# CREATE_COMPLETE                                   AWS::CloudFormation::Stack                        SSOSync                                           -
# -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

# Successfully created/updated stack - SSOSync in us-east-1

Test the SSOSync Lambda Application (Lambda Function Stack)

Testing locally if deployed parameters are properly configured.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
$ echo '{}' | sam local invoke --event - "SSOSyncFunction"

# Reading invoke payload from stdin (you can also pass it from file with --event)
# Invoking dist/ssosync_linux_amd64_v1/ssosync (go1.x)
# Local image was not found.
# Removing rapid images for repo public.ecr.aws/sam/emulation-go1.x
# Building image.............................................................
# Using local image: public.ecr.aws/lambda/go:1-rapid-x86_64.

# Mounting /path/to/awslabs/ssosync/.aws-sam/build/SSOSyncFunction as /var/task:ro,delegated inside runtime container
# START RequestId: **************************** Version: $LATEST
# time="2023-02-12T17:39:35Z" level=info msg="Executing as Lambda"
# time="2023-02-12T17:39:38Z" level=info msg="Syncing AWS users and groups from Google Workspace SAML Application"
# time="2023-02-12T17:39:38Z" level=info msg=syncing sync_method=groups
# time="2023-02-12T17:39:38Z" level=info msg="get google groups" query=
# time="2023-02-12T17:39:39Z" level=debug msg="preparing list of google users and then google groups and their members"
# time="2023-02-12T17:39:39Z" level=debug msg="get group members from google" group=administrator
# time="2023-02-12T17:39:39Z" level=debug msg="get users" group=administrator
# time="2023-02-12T17:39:39Z" level=debug msg="get user" group=administrator id=johndoe@domain.tld
# time="2023-02-12T17:39:40Z" level=info msg="get existing aws groups"
# time="2023-02-12T17:39:41Z" level=info msg="get existing aws users"
# time="2023-02-12T17:39:42Z" level=info msg="get active status for aws users"
# time="2023-02-12T17:39:43Z" level=info msg="preparing map of user id's to user"
# time="2023-02-12T17:39:43Z" level=debug msg="preparing list of aws groups and their members"
# time="2023-02-12T17:39:43Z" level=info msg="syncing changes"
# time="2023-02-12T17:39:43Z" level=debug msg="deleting aws users deleted in google"
# time="2023-02-12T17:39:43Z" level=debug msg="updating aws users updated in google"
# time="2023-02-12T17:39:43Z" level=debug msg="creating aws users added in google"
# time="2023-02-12T17:39:43Z" level=debug msg="creating aws groups added in google"
# time="2023-02-12T17:39:43Z" level=debug msg="validating groups members, equals in aws and google"
# time="2023-02-12T17:39:43Z" level=debug msg="finding user" group=administrator user=johndoe@domain.tld
# time="2023-02-12T17:39:44Z" level=debug msg="checking user is in group already" group=administrator user=johndoe@domain.tld
# time="2023-02-12T17:39:44Z" level=debug msg="delete aws groups deleted in google"
# time="2023-02-12T17:39:44Z" level=info msg="sync completed"
# "Success"END RequestId: ****************************
# REPORT RequestId: ****************************	Init Duration: 0.16 ms	Duration: 8748.82 ms	Billed Duration: 8749 ms	Memory Size: 128 MB	Max Memory Used: 128 MB

Test the production deployed Lambda Application and check the rest of the events in the AWS Cloudwatch log groups application streams.

1
2
3
4
5
6
7
8
9
$ aws lambda invoke --function-name SSOSync-SSOSyncFunction-************ --payload '{}' response.json

# {
#     "StatusCode": 200,
#     "ExecutedVersion": "$LATEST"
# }

# $ cat response.json
# "Success"

:tada: Let the Lambda Application and its EventBridge periodic settings execute the syncing from the Google Workspace Directory to AWS IAM Identity Center do the rest.

Other Deployment Options

You can also deploy the SSO Sync Lambda Application through AWS Console using the AWS Serverless Application Repository. Just fill in the required parameters and deploy. Then Wait for the AWS Cloudformation to automate the deployment process.

This post is licensed under CC BY 4.0 by the author.