Last active
February 10, 2021 21:37
-
-
Save alsmola/58a0f729e0960208df20e1ad11fcf007 to your computer and use it in GitHub Desktop.
List Okta account access to AWS IAM roles
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"context" | |
"encoding/csv" | |
"errors" | |
"fmt" | |
"log" | |
"os" | |
"regexp" | |
"github.com/okta/okta-sdk-golang/v2/okta" | |
"github.com/okta/okta-sdk-golang/v2/okta/query" | |
) | |
// Map of Okta email to array of AWS IAM roles | |
type userRoles map[string][]string | |
func main() { | |
ctx := context.Background() | |
oktaOrgURL := "https://yoursubdomain.okta.com" | |
ctx, client, err := okta.NewClient(ctx, okta.WithOrgUrl(oktaOrgURL), okta.WithToken("your-okta-api-token")) | |
if err != nil { | |
panic(err) | |
} | |
applications, err := getOktaApps(ctx, client) | |
if err != nil { | |
panic(err) | |
} | |
awsAppID := "" | |
for _, app := range applications { | |
if app.Name == "amazon_aws" { | |
awsAppID = app.Id | |
} | |
} | |
if awsAppID == "" { | |
panic(errors.New("No AWS application found")) | |
} | |
appUsers, err := getOktaUsersForAWS(ctx, client, awsAppID) | |
if err != nil { | |
panic(err) | |
} | |
awsAccounts := []string{ | |
"your-aws-account-names", | |
} | |
writers := map[string]*csv.Writer{} | |
for _, awsAccount := range awsAccounts { | |
file, err := os.Create(fmt.Sprintf("%s.csv", awsAccount)) | |
if err != nil { | |
panic(err) | |
} | |
writers[awsAccount] = csv.NewWriter(file) | |
} | |
accountsUsersRoles := map[string]userRoles{} | |
for email, roles := range appUsers { | |
for _, role := range roles { | |
roleRegex := regexp.MustCompile(`\[(.*)\]\s--\s(.*)`) | |
matches := roleRegex.FindStringSubmatch(role) | |
if len(matches) < 3 { | |
panic(fmt.Errorf("Couldn't parse role: %s", role)) | |
} | |
account := matches[1] | |
roleName := matches[2] | |
r := accountsUsersRoles[account][email] | |
r = append(r, roleName) | |
if accountsUsersRoles[account] == nil { | |
accountsUsersRoles[account] = userRoles{} | |
} | |
accountsUsersRoles[account][email] = r | |
} | |
} | |
for account, ur := range accountsUsersRoles { | |
for email, roles := range ur { | |
line := []string{email} | |
line = append(line, roles...) | |
err := writers[account].Write(line) | |
if err != nil { | |
panic(err) | |
} | |
} | |
} | |
for _, w := range writers { | |
w.Flush() | |
} | |
log.Println("Files created.") | |
} | |
func getOktaUsersForAWS(ctx context.Context, client *okta.Client, appID string) (userRoles, error) { | |
users := map[string][]string{} | |
// Get users assigned directly to application | |
appUsers, resp, err := client.Application.ListApplicationUsers(ctx, appID, nil) | |
if err != nil { | |
return users, err | |
} | |
for resp.HasNextPage() { | |
var nextAppUsers []*okta.AppUser | |
resp, err = resp.Next(ctx, &nextAppUsers) | |
if err != nil { | |
return users, err | |
} | |
appUsers = append(appUsers, nextAppUsers...) | |
} | |
for _, appUser := range appUsers { | |
userProfile := appUser.Profile.(map[string]interface{}) | |
email := userProfile["email"].(string) | |
roles := []string{} | |
for _, r := range userProfile["samlRoles"].([]interface{}) { | |
roles = append(roles, r.(string)) | |
} | |
users[email] = roles | |
} | |
// Get users assigned to application via groups | |
groups, resp, err := client.Application.ListApplicationGroupAssignments(ctx, appID, nil) | |
if err != nil { | |
return users, err | |
} | |
for resp.HasNextPage() { | |
var nextGroups []*okta.ApplicationGroupAssignment | |
resp, err = resp.Next(ctx, &nextGroups) | |
if err != nil { | |
return users, err | |
} | |
groups = append(groups, nextGroups...) | |
} | |
var groupUsers []*okta.User | |
for _, group := range groups { | |
roles := []string{} | |
profile := group.Profile.(map[string]interface{}) | |
samlRoles := profile["samlRoles"].([]interface{}) | |
for _, r := range samlRoles { | |
roles = append(roles, r.(string)) | |
} | |
groupUsers, resp, err = client.Group.ListGroupUsers(ctx, group.Id, nil) | |
if err != nil { | |
return users, err | |
} | |
for resp.HasNextPage() { | |
var nextGroupUsers []*okta.User | |
resp, err = resp.Next(ctx, &nextGroupUsers) | |
if err != nil { | |
return users, err | |
} | |
groupUsers = append(groupUsers, nextGroupUsers...) | |
} | |
for _, groupUser := range groupUsers { | |
userProfile := *(groupUser.Profile) | |
email := userProfile["email"].(string) | |
existingRoles, ok := users[email] | |
if ok { | |
users[email] = union(existingRoles, roles) | |
} | |
} | |
} | |
return users, err | |
} | |
func getOktaApps(ctx context.Context, client *okta.Client) ([]*okta.Application, error) { | |
applications := []*okta.Application{} | |
params := query.Params{ | |
Filter: "status eq \"ACTIVE\"", | |
} | |
apps, resp, err := client.Application.ListApplications(ctx, ¶ms) | |
if err != nil { | |
log.Println("Can't get apps") | |
return applications, err | |
} | |
applications = transformApplications(apps) | |
for resp.HasNextPage() { | |
var nextApps []*okta.Application | |
resp, err = resp.Next(ctx, &nextApps) | |
if err != nil { | |
return applications, err | |
} | |
applications = append(applications, nextApps...) | |
} | |
return applications, nil | |
} | |
func transformApplications(values []okta.App) []*okta.Application { | |
var tValues []*okta.Application | |
for _, v := range values { | |
tValues = append(tValues, v.(*okta.Application)) | |
} | |
return tValues | |
} | |
func union(a, b []string) []string { | |
m := make(map[string]bool) | |
for _, item := range a { | |
m[item] = true | |
} | |
for _, item := range b { | |
if _, ok := m[item]; !ok { | |
a = append(a, item) | |
} | |
} | |
return a | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment