diff --git a/aws/plugin.go b/aws/plugin.go index 5a138dd0e..996bcffe2 100644 --- a/aws/plugin.go +++ b/aws/plugin.go @@ -165,6 +165,7 @@ func Plugin(ctx context.Context) *plugin.Plugin { "aws_cognito_identity_pool": tableAwsCognitoIdentityPool(ctx), "aws_cognito_identity_provider": tableAwsCognitoIdentityProvider(ctx), "aws_cognito_user_pool": tableAwsCognitoUserPool(ctx), + "aws_cognito_user_group": tableAwsCognitoUserGroup(ctx), "aws_config_aggregate_authorization": tableAwsConfigAggregateAuthorization(ctx), "aws_config_configuration_recorder": tableAwsConfigConfigurationRecorder(ctx), "aws_config_conformance_pack": tableAwsConfigConformancePack(ctx), diff --git a/aws/table_aws_cognito_user_group.go b/aws/table_aws_cognito_user_group.go new file mode 100644 index 000000000..99c2df624 --- /dev/null +++ b/aws/table_aws_cognito_user_group.go @@ -0,0 +1,237 @@ +package aws + +import ( + "context" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/cognitoidentityprovider" + "github.com/aws/aws-sdk-go-v2/service/cognitoidentityprovider/types" + + "github.com/turbot/steampipe-plugin-sdk/v5/grpc/proto" + "github.com/turbot/steampipe-plugin-sdk/v5/plugin" + "github.com/turbot/steampipe-plugin-sdk/v5/plugin/transform" +) + +//// TABLE DEFINITION + +func tableAwsCognitoUserGroup(_ context.Context) *plugin.Table { + return &plugin.Table{ + Name: "aws_cognito_user_group", + Description: "AWS Cognito User Group", + Get: &plugin.GetConfig{ + KeyColumns: plugin.AllColumns([]string{"group_name", "user_pool_id"}), + Hydrate: getCognitoUserGroup, + Tags: map[string]string{"service": "cognito-idp", "action": "GetGroup"}, + }, + List: &plugin.ListConfig{ + ParentHydrate: listCognitoUserPools, + Hydrate: listCognitoUserGroups, + Tags: map[string]string{"service": "cognito-idp", "action": "ListGroups"}, + KeyColumns: []*plugin.KeyColumn{ + {Name: "user_pool_id", Require: plugin.Optional}, + }, + }, + GetMatrixItemFunc: SupportedRegionMatrix(AWS_COGNITO_IDP_SERVICE_ID), + Columns: awsRegionalColumns([]*plugin.Column{ + { + Name: "group_name", + Description: "The name of the group.", + Type: proto.ColumnType_STRING, + }, + { + Name: "user_pool_id", + Description: "The user pool ID for the user pool.", + Type: proto.ColumnType_STRING, + }, + { + Name: "description", + Description: "A string containing the description of the group.", + Type: proto.ColumnType_STRING, + }, + { + Name: "creation_date", + Description: "The date and time when the group was created.", + Type: proto.ColumnType_TIMESTAMP, + }, + { + Name: "last_modified_date", + Description: "The date and time when the group was last modified.", + Type: proto.ColumnType_TIMESTAMP, + Transform: transform.FromField("LastModifiedDate").Transform(transform.NullIfZeroValue), + }, + { + Name: "precedence", + Description: "A non-negative integer value that specifies the precedence of this group relative to the other groups that a user can belong to in the user pool.", + Type: proto.ColumnType_INT, + }, + { + Name: "role_arn", + Description: "The role Amazon Resource Name (ARN) for the group.", + Type: proto.ColumnType_STRING, + }, + + // Standard columns + { + Name: "title", + Description: resourceInterfaceDescription("title"), + Type: proto.ColumnType_STRING, + Transform: transform.FromField("GroupName"), + }, + { + Name: "akas", + Description: resourceInterfaceDescription("akas"), + Type: proto.ColumnType_JSON, + Hydrate: getCognitoUserGroupAkas, + Transform: transform.FromValue(), + }, + }), + } +} + +//// LIST FUNCTION + +func listCognitoUserGroups(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateData) (interface{}, error) { + // Get user pool details from hydrate data + var userPoolID string + if h.Item != nil { + userPoolData, ok := h.Item.(types.UserPoolDescriptionType) + if ok { + userPoolID = *userPoolData.Id + } + } + + // Check if a specific user_pool_id has been provided in the query + if d.EqualsQualString("user_pool_id") != "" && userPoolID == d.EqualsQualString("user_pool_id") { + return nil, nil + } + + // Return if no user pool is found + if userPoolID == "" { + return nil, nil + } + + // Create session + svc, err := CognitoIdentityProviderClient(ctx, d) + if err != nil { + plugin.Logger(ctx).Error("aws_cognito_user_group.listCognitoUserGroups", "connection_error", err) + return nil, err + } + + if svc == nil { + // Unsupported region check + return nil, nil + } + + // Limiting the results + maxLimit := int32(60) + limit := d.QueryContext.Limit + if d.QueryContext.Limit != nil { + if *limit < int64(maxLimit) { + maxLimit = int32(*limit) + } + } + + input := &cognitoidentityprovider.ListGroupsInput{ + UserPoolId: aws.String(userPoolID), + Limit: aws.Int32(maxLimit), + } + + // List call + paginator := cognitoidentityprovider.NewListGroupsPaginator(svc, input, func(o *cognitoidentityprovider.ListGroupsPaginatorOptions) { + o.Limit = maxLimit + o.StopOnDuplicateToken = true + }) + + for paginator.HasMorePages() { + // apply rate limiting + d.WaitForListRateLimit(ctx) + + output, err := paginator.NextPage(ctx) + if err != nil { + plugin.Logger(ctx).Error("aws_cognito_user_group.listCognitoUserGroups", "api_error", err) + return nil, err + } + + for _, item := range output.Groups { + d.StreamListItem(ctx, item) + + // Context may get cancelled due to manual cancellation or if the limit has been reached + if d.RowsRemaining(ctx) == 0 { + return nil, nil + } + } + } + + return nil, nil +} + +//// HYDRATE FUNCTIONS + +func getCognitoUserGroup(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateData) (interface{}, error) { + var groupName, userPoolID string + + if h.Item != nil { + data := h.Item.(types.GroupType) + groupName = *data.GroupName + userPoolID = *data.UserPoolId + } else { + groupName = d.EqualsQualString("group_name") + userPoolID = d.EqualsQualString("user_pool_id") + } + + // Empty check for required parameters + if groupName == "" || userPoolID == "" { + return nil, nil + } + + // Create service + svc, err := CognitoIdentityProviderClient(ctx, d) + if err != nil { + plugin.Logger(ctx).Error("aws_cognito_user_group.getCognitoUserGroup", "connection_error", err) + return nil, err + } + + if svc == nil { + // Unsupported region check + return nil, nil + } + + // Build the params + params := &cognitoidentityprovider.GetGroupInput{ + GroupName: aws.String(groupName), + UserPoolId: aws.String(userPoolID), + } + + // Get call + data, err := svc.GetGroup(ctx, params) + if err != nil { + plugin.Logger(ctx).Error("aws_cognito_user_group.getCognitoUserGroup", "api_error", err) + return nil, err + } + + if data != nil { + return *data.Group, nil + } + + return nil, nil +} + +func getCognitoUserGroupAkas(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateData) (interface{}, error) { + group := h.Item.(types.GroupType) + region := d.EqualsQualString(matrixKeyRegion) + + // Get account details + commonData, err := getCommonColumns(ctx, d, h) + if err != nil { + plugin.Logger(ctx).Error("aws_cognito_user_group.getCognitoUserGroupAkas", "common_data_error", err) + return nil, err + } + + commonColumnData := commonData.(*awsCommonColumnData) + accountID := commonColumnData.AccountId + + // Generate user group ARN + userGroupArn := "arn:aws:cognito-idp:" + region + ":" + accountID + ":userpool/" + *group.UserPoolId + "/group/" + *group.GroupName + + return []string{userGroupArn}, nil +} diff --git a/docs/tables/aws_cognito_user_group.md b/docs/tables/aws_cognito_user_group.md new file mode 100644 index 000000000..03cddf4e6 --- /dev/null +++ b/docs/tables/aws_cognito_user_group.md @@ -0,0 +1,158 @@ +--- +title: "Steampipe Table: aws_cognito_user_group - Query AWS Cognito User Groups using SQL" +description: "Allows users to query AWS Cognito User Groups to retrieve information about group configurations, permissions, and associated user pools." +folder: "Cognito" +--- + +# aws_cognito_user_group + +AWS Cognito user groups provide a way to manage and categorize users in Amazon Cognito user pools. User groups can be used to create collections of users that have similar permissions and characteristics. This allows administrators to set permissions for multiple users at once, assign IAM roles to users, and define precedence for users who might be in multiple groups. + +## Table Usage Guide + +The `aws_cognito_user_group` table provides insights into user groups within Amazon Cognito user pools. As a security administrator or developer, you can query this table to retrieve detailed information about group configurations, including IAM role assignments, precedence values, and descriptions. This can be useful for auditing user permissions, ensuring proper group configurations, and managing access controls within your Cognito user pools. + +## Examples + +### Basic info +This query helps you understand the basic structure and distribution of all Cognito user groups across your user pools. + +```sql+postgres +select + group_name, + user_pool_id, + description, + precedence, + creation_date, + region +from + aws_cognito_user_group; +``` + +```sql+sqlite +select + group_name, + user_pool_id, + description, + precedence, + creation_date, + region +from + aws_cognito_user_group; +``` + +### List all user groups in a specific user pool +This query retrieves all user groups that belong to a specific Cognito user pool, which is useful for auditing access controls within a particular user pool. + +```sql+postgres +select + group_name, + description, + role_arn, + precedence, + creation_date +from + aws_cognito_user_group +where + user_pool_id = 'us-east-1_example123'; +``` + +```sql+sqlite +select + group_name, + description, + role_arn, + precedence, + creation_date +from + aws_cognito_user_group +where + user_pool_id = 'us-east-1_example123'; +``` + +### Find user groups with assigned IAM roles +This example identifies all user groups that have IAM roles assigned to them, which helps in reviewing role-based access control configurations. + +```sql+postgres +select + group_name, + user_pool_id, + role_arn, + precedence, + region +from + aws_cognito_user_group +where + role_arn is not null; +``` + +```sql+sqlite +select + group_name, + user_pool_id, + role_arn, + precedence, + region +from + aws_cognito_user_group +where + role_arn is not null; +``` + +### Groups created in the last 30 days +This query identifies recently created user groups in your Cognito user pools, which can help track changes in your identity management infrastructure. + +```sql+postgres +select + group_name, + user_pool_id, + description, + creation_date, + region +from + aws_cognito_user_group +where + creation_date > current_date - interval '30 days'; +``` + +```sql+sqlite +select + group_name, + user_pool_id, + description, + creation_date, + region +from + aws_cognito_user_group +where + creation_date > date('now', '-30 days'); +``` + +### Count of user groups per user pool +This query provides a count of how many user groups exist in each Cognito user pool, helping you understand the distribution and complexity of your group management. + +```sql+postgres +select + user_pool_id, + count(*) as group_count, + region +from + aws_cognito_user_group +group by + user_pool_id, region +order by + group_count desc; +``` + +```sql+sqlite +select + user_pool_id, + count(*) as group_count, + region +from + aws_cognito_user_group +group by + user_pool_id, region +order by + group_count desc; +```