Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes from pull #45 and #47 #2

Merged
merged 1 commit into from
Aug 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

> Helping you populate AWS SSO directly with your Google Apps users

SSO Sync will run on any platform that Go can build for. It is available in the [AWS Serverless Application Repository](https://console.aws.amazon.com/lambda/home#/create/app?applicationId=arn:aws:serverlessrepo:us-east-2:004480582608:applications/SSOSync)
SSO Sync will run on any platform that Go can build for. It is available in the [AWS Serverless Application Repository](https://console.aws.amazon.com/lambda/home#/create/app?applicationId=arn:aws:serverlessrepo:eu-west-1:084703771460:applications/ssosync).

> :warning: there are breaking changes for versions `>= 0.02`

Expand Down Expand Up @@ -133,8 +133,12 @@ Flags:

The function has `two behaviour` and these are controlled by the `--sync-method` flag, this behavior could be

1. `groups`: __(default)__ The sync procedure work base on Groups, gets the Google Workspace groups and their members, then creates in AWS SSO the users (members of the Google Workspace groups), then the groups and at the end assign the users to their respective groups.
2. `users_groups`: __(original behavior, previous versions)__ The sync procedure is simple, gets the Google Workspace users and creates these in AWS SSO Users; then gets Google Workspace groups and creates these in AWS SSO Groups and assigns users to belong to the AWS SSO Groups.
1. `groups`: __(default)__
* The sync procedure work base on Groups, gets the Google Workspace groups and their members, then creates in AWS SSO the users (members of the Google Workspace groups), then the groups and at the end assign the users to their respective groups.
* This method use: `Google Workspace groups name` --> `AWS SSO groups name`
2. `users_groups`: __(original behavior, previous versions)__
* The sync procedure is simple, gets the Google Workspace users and creates these in AWS SSO Users; then gets Google Workspace groups and creates these in AWS SSO Groups and assigns users to belong to the AWS SSO Groups.
* This method use: `Google Workspace groups email` --> `AWS SSO groups name`

Flags Notes:

Expand All @@ -148,6 +152,7 @@ NOTES:

1. Depending on the number of users and groups you have, maybe you can get `AWS SSO SCIM API rate limits errors`, and more frequently happens if you execute the sync many times in a short time.
2. Depending on the number of users and groups you have, `--debug` flag generate too much logs lines in your AWS Lambda function. So test it in locally with the `--debug` flag enabled and disable it when you use a AWS Lambda function.
3. `--sync-method "Groups"` and `--sync-method "users_groups"` are incompatible, because the first use the Google group name as an AWS group name and the second one use the Google group email, take this into consideration.

## AWS Lambda Usage

Expand All @@ -157,7 +162,7 @@ the pricing for AWS Lambda and CloudWatch before continuing.
Running ssosync once means that any changes to your Google directory will not appear in
AWS SSO. To sync. regularly, you can run ssosync via AWS Lambda.

:warning: You find it in the [AWS Serverless Application Repository](https://eu-west-1.console.aws.amazon.com/lambda/home#/create/app?applicationId=arn:aws:serverlessrepo:us-east-2:004480582608:applications/SSOSync).
:warning: You find it in the [AWS Serverless Application Repository](https://console.aws.amazon.com/lambda/home#/create/app?applicationId=arn:aws:serverlessrepo:eu-west-1:084703771460:applications/ssosync).

## SAM

Expand Down
20 changes: 18 additions & 2 deletions internal/aws/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ func (c *client) IsUserInGroup(u *User, g *Group) (bool, error) {
startURL.RawQuery = q.Encode()
resp, err := c.sendRequest(http.MethodGet, startURL.String())
if err != nil {
log.WithFields(log.Fields{"user": u.Username, "group": g.DisplayName}).Error(string(resp))
return false, err
}

Expand Down Expand Up @@ -222,10 +223,13 @@ func (c *client) groupChangeOperation(op OperationType, u *User, g *Group) error
}

startURL.Path = path.Join(startURL.Path, fmt.Sprintf("/Groups/%s", g.ID))
_, err = c.sendRequestWithBody(http.MethodPatch, startURL.String(), *gc)

resp, err := c.sendRequestWithBody(http.MethodPatch, startURL.String(), *gc)
if err != nil {
log.WithFields(log.Fields{"operations": op, "user": u.Username, "group": g.DisplayName}).Error(string(resp))
return err
}
log.WithFields(log.Fields{"operations": op, "user": u.Username, "group": g.DisplayName}).Debug(string(resp))

return nil
}
Expand Down Expand Up @@ -257,6 +261,7 @@ func (c *client) FindUserByEmail(email string) (*User, error) {

resp, err := c.sendRequest(http.MethodGet, startURL.String())
if err != nil {
log.WithFields(log.Fields{"email": email}).Error(string(resp))
return nil, err
}

Expand Down Expand Up @@ -284,6 +289,7 @@ func (c *client) FindUserByID(id string) (*User, error) {

resp, err := c.sendRequest(http.MethodGet, startURL.String())
if err != nil {
log.WithFields(log.Fields{"id": id}).Error(string(resp))
return nil, err
}

Expand Down Expand Up @@ -317,6 +323,7 @@ func (c *client) FindGroupByDisplayName(name string) (*Group, error) {

resp, err := c.sendRequest(http.MethodGet, startURL.String())
if err != nil {
log.WithFields(log.Fields{"name": name}).Error(string(resp))
return nil, err
}

Expand Down Expand Up @@ -348,6 +355,7 @@ func (c *client) CreateUser(u *User) (*User, error) {
startURL.Path = path.Join(startURL.Path, "/Users")
resp, err := c.sendRequestWithBody(http.MethodPost, startURL.String(), *u)
if err != nil {
log.WithFields(log.Fields{"user": u.Username}).Error(string(resp))
return nil, err
}

Expand Down Expand Up @@ -378,6 +386,7 @@ func (c *client) UpdateUser(u *User) (*User, error) {
startURL.Path = path.Join(startURL.Path, fmt.Sprintf("/Users/%s", u.ID))
resp, err := c.sendRequestWithBody(http.MethodPut, startURL.String(), *u)
if err != nil {
log.WithFields(log.Fields{"user": u.Username}).Error(string(resp))
return nil, err
}

Expand Down Expand Up @@ -405,11 +414,14 @@ func (c *client) DeleteUser(u *User) error {
}

startURL.Path = path.Join(startURL.Path, fmt.Sprintf("/Users/%s", u.ID))
_, err = c.sendRequest(http.MethodDelete, startURL.String())
resp, err := c.sendRequest(http.MethodDelete, startURL.String())
if err != nil {
log.WithFields(log.Fields{"user": u.Username}).Error(string(resp))
return err
}

log.WithFields(log.Fields{"user": u.Username}).Debug(string(resp))

return nil
}

Expand All @@ -428,6 +440,7 @@ func (c *client) CreateGroup(g *Group) (*Group, error) {
startURL.Path = path.Join(startURL.Path, "/Groups")
resp, err := c.sendRequestWithBody(http.MethodPost, startURL.String(), *g)
if err != nil {
log.WithFields(log.Fields{"group": g.DisplayName}).Error(string(resp))
return nil, err
}

Expand Down Expand Up @@ -471,6 +484,7 @@ func (c *client) GetGroups() ([]*Group, error) {

resp, err := c.sendRequest(http.MethodGet, startURL.String())
if err != nil {
log.Error(string(resp))
return nil, err
}

Expand Down Expand Up @@ -513,6 +527,7 @@ func (c *client) GetGroupMembers(g *Group) ([]*User, error) {

resp, err := c.sendRequest(http.MethodGet, startURL.String())
if err != nil {
log.WithFields(log.Fields{"group": g.DisplayName}).Error(string(resp))
return nil, err
}

Expand Down Expand Up @@ -548,6 +563,7 @@ func (c *client) GetUsers() ([]*User, error) {

resp, err := c.sendRequest(http.MethodGet, startURL.String())
if err != nil {
log.Error(string(resp))
return nil, err
}

Expand Down
6 changes: 3 additions & 3 deletions internal/google/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ func (c *client) GetDeletedUsers() ([]*admin.User, error) {
// GetGroupMembers will get the members of the group specified
func (c *client) GetGroupMembers(g *admin.Group) ([]*admin.Member, error) {
m := make([]*admin.Member, 0)
err := c.service.Members.List(g.Id).Pages(context.TODO(), func(members *admin.Members) error {
err := c.service.Members.List(g.Id).Pages(c.ctx, func(members *admin.Members) error {
m = append(m, members.Members...)
return nil
})
Expand Down Expand Up @@ -134,12 +134,12 @@ func (c *client) GetGroups(query string) ([]*admin.Group, error) {
var err error

if query != "" {
err = c.service.Groups.List().Customer("my_customer").Query(query).Pages(context.TODO(), func(groups *admin.Groups) error {
err = c.service.Groups.List().Customer("my_customer").Query(query).Pages(c.ctx, func(groups *admin.Groups) error {
g = append(g, groups.Groups...)
return nil
})
} else {
err = c.service.Groups.List().Customer("my_customer").Pages(context.TODO(), func(groups *admin.Groups) error {
err = c.service.Groups.List().Customer("my_customer").Pages(c.ctx, func(groups *admin.Groups) error {
g = append(g, groups.Groups...)
return nil
})
Expand Down
45 changes: 29 additions & 16 deletions internal/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -277,12 +277,17 @@ func (s *syncGSuite) SyncGroupsUsers(query string) error {
if err != nil {
return err
}

// Filter groups
filteredGoogleGroups := []*admin.Group{}
for _, g := range googleGroups {

// bacaudse is in flag --ignore-groups
if s.ignoreGroup(g.Email) {
log.WithField("group", g.Email).Debug("ignoring group")
log.WithField("group", g.Email).Warn("ignoring group, using --ignore-groups")
continue
}

filteredGoogleGroups = append(filteredGoogleGroups, g)
}
googleGroups = filteredGoogleGroups
Expand Down Expand Up @@ -359,14 +364,18 @@ func (s *syncGSuite) SyncGroupsUsers(query string) error {
// add aws users (added in google)
log.Debug("creating aws users added in google")
for _, awsUser := range addAWSUsers {

log := log.WithFields(log.Fields{"user": awsUser.Username})

log.Info("creating user")
_, err := s.aws.CreateUser(awsUser)
if err != nil {
log.Error("error creating user")
return err
// Due to limits in users listing, the user may already exists
// see https://docs.aws.amazon.com/singlesignon/latest/developerguide/listusers.html
user, _ := s.aws.FindUserByEmail(awsUser.Username)
if user == nil {
log := log.WithFields(log.Fields{"user": awsUser.Username})

log.Info("creating user")
_, err := s.aws.CreateUser(awsUser)
if err != nil {
log.Error("error creating user")
return err
}
}
}

Expand All @@ -377,7 +386,7 @@ func (s *syncGSuite) SyncGroupsUsers(query string) error {
log := log.WithFields(log.Fields{"group": awsGroup.DisplayName})

log.Info("creating group")
_, err := s.aws.CreateGroup(awsGroup)
awsGroupFull, err := s.aws.CreateGroup(awsGroup)
if err != nil {
log.Error("creating group")
return err
Expand All @@ -394,7 +403,7 @@ func (s *syncGSuite) SyncGroupsUsers(query string) error {
}

log.WithField("user", awsUserFull.Username).Info("adding user to group")
err = s.aws.AddUserToGroup(awsUserFull, awsGroup)
err = s.aws.AddUserToGroup(awsUserFull, awsGroupFull)
if err != nil {
return err
}
Expand Down Expand Up @@ -508,12 +517,16 @@ func (s *syncGSuite) getGoogleGroupsAndUsers(googleGroups []*admin.Group) ([]*ad
return nil, nil, err
}

membersUsers = append(membersUsers, u[0])

_, ok := gUniqUsers[m.Email]
if !ok {
gUniqUsers[m.Email] = u[0]
if len(u) != 0 {
membersUsers = append(membersUsers, u[0])
_, ok := gUniqUsers[m.Email]
if !ok {
gUniqUsers[m.Email] = u[0]
}
} else {
log.WithField("member", m.Email).Warn("ignoring group member because it is not a user, looks like a group inside the group")
}

}
gGroupsUsers[g.Name] = membersUsers
}
Expand Down
2 changes: 1 addition & 1 deletion internal/sync_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ package internal

import (
"encoding/json"
"log"
"reflect"
"testing"

"github.com/awslabs/ssosync/internal/aws"
log "github.com/sirupsen/logrus"
admin "google.golang.org/api/admin/directory/v1"
)

Expand Down