AWS SDK を使用した Amazon Cognito ユーザー認証後の Lambda 関数を使用したカスタムアクティビティデータの書き込み - AWS SDK コード例

Doc AWS SDK Examples リポジトリには、他にも SDK の例があります。 AWS GitHub

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

AWS SDK を使用した Amazon Cognito ユーザー認証後の Lambda 関数を使用したカスタムアクティビティデータの書き込み

次のコード例は、Amazon Cognito ユーザー認証後に Lambda 関数を使用してカスタムアクティビティデータを書き込む方法を示しています。

  • 管理者機能を使用して、ユーザープールにユーザーを追加します。

  • PostAuthentication トリガーの Lambda 関数を呼び出すようにユーザープールを設定します。

  • 新しいユーザーを Amazon Cognito にサインインします。

  • Lambda 関数は、カスタム情報を CloudWatch Logs と DynamoDB テーブルに書き込みます。

  • DynamoDB テーブルからカスタムデータを取得して表示し、リソースをクリーンアップします。

Go
SDK for Go V2
注記

には他にもがあります GitHub。AWS コード例リポジトリ で全く同じ例を見つけて、設定と実行の方法を確認してください。

コマンドプロンプトからインタラクティブのシナリオを実行します。

// ActivityLog separates the steps of this scenario into individual functions so that // they are simpler to read and understand. type ActivityLog struct { helper IScenarioHelper questioner demotools.IQuestioner resources Resources cognitoActor *actions.CognitoActions } // NewActivityLog constructs a new activity log runner. func NewActivityLog(sdkConfig aws.Config, questioner demotools.IQuestioner, helper IScenarioHelper) ActivityLog { scenario := ActivityLog{ helper: helper, questioner: questioner, resources: Resources{}, cognitoActor: &actions.CognitoActions{CognitoClient: cognitoidentityprovider.NewFromConfig(sdkConfig)}, } scenario.resources.init(scenario.cognitoActor, questioner) return scenario } // AddUserToPool selects a user from the known users table and uses administrator credentials to add the user to the user pool. func (runner *ActivityLog) AddUserToPool(userPoolId string, tableName string) (string, string) { log.Println("To facilitate this example, let's add a user to the user pool using administrator privileges.") users, err := runner.helper.GetKnownUsers(tableName) if err != nil { panic(err) } user := users.Users[0] log.Printf("Adding known user %v to the user pool.\n", user.UserName) err = runner.cognitoActor.AdminCreateUser(userPoolId, user.UserName, user.UserEmail) if err != nil { panic(err) } pwSet := false password := runner.questioner.AskPassword("\nEnter a password that has at least eight characters, uppercase, lowercase, numbers and symbols.\n"+ "(the password will not display as you type):", 8) for !pwSet { log.Printf("\nSetting password for user '%v'.\n", user.UserName) err = runner.cognitoActor.AdminSetUserPassword(userPoolId, user.UserName, password) if err != nil { var invalidPassword *types.InvalidPasswordException if errors.As(err, &invalidPassword) { password = runner.questioner.AskPassword("\nEnter another password:", 8) } else { panic(err) } } else { pwSet = true } } log.Println(strings.Repeat("-", 88)) return user.UserName, password } // AddActivityLogTrigger adds a Lambda handler as an invocation target for the PostAuthentication trigger. func (runner *ActivityLog) AddActivityLogTrigger(userPoolId string, activityLogArn string) { log.Println("Let's add a Lambda function to handle the PostAuthentication trigger from Cognito.\n" + "This trigger happens after a user is authenticated, and lets your function take action, such as logging\n" + "the outcome.") err := runner.cognitoActor.UpdateTriggers( userPoolId, actions.TriggerInfo{Trigger: actions.PostAuthentication, HandlerArn: aws.String(activityLogArn)}) if err != nil { panic(err) } runner.resources.triggers = append(runner.resources.triggers, actions.PostAuthentication) log.Printf("Lambda function %v added to user pool %v to handle PostAuthentication Cognito trigger.\n", activityLogArn, userPoolId) log.Println(strings.Repeat("-", 88)) } // SignInUser signs in as the specified user. func (runner *ActivityLog) SignInUser(clientId string, userName string, password string) { log.Printf("Now we'll sign in user %v and check the results in the logs and the DynamoDB table.", userName) runner.questioner.Ask("Press Enter when you're ready.") authResult, err := runner.cognitoActor.SignIn(clientId, userName, password) if err != nil { panic(err) } log.Println("Sign in successful.", "The PostAuthentication Lambda handler writes custom information to CloudWatch Logs.") runner.resources.userAccessTokens = append(runner.resources.userAccessTokens, *authResult.AccessToken) } // GetKnownUserLastLogin gets the login info for a user from the Amazon DynamoDB table and displays it. func (runner *ActivityLog) GetKnownUserLastLogin(tableName string, userName string) { log.Println("The PostAuthentication handler also writes login data to the DynamoDB table.") runner.questioner.Ask("Press Enter when you're ready to continue.") users, err := runner.helper.GetKnownUsers(tableName) if err != nil { panic(err) } for _, user := range users.Users { if user.UserName == userName { log.Println("The last login info for the user in the known users table is:") log.Printf("\t%+v", *user.LastLogin) } } log.Println(strings.Repeat("-", 88)) } // Run runs the scenario. func (runner *ActivityLog) Run(stackName string) { defer func() { if r := recover(); r != nil { log.Println("Something went wrong with the demo.") runner.resources.Cleanup() } }() log.Println(strings.Repeat("-", 88)) log.Printf("Welcome\n") log.Println(strings.Repeat("-", 88)) stackOutputs, err := runner.helper.GetStackOutputs(stackName) if err != nil { panic(err) } runner.resources.userPoolId = stackOutputs["UserPoolId"] runner.helper.PopulateUserTable(stackOutputs["TableName"]) userName, password := runner.AddUserToPool(stackOutputs["UserPoolId"], stackOutputs["TableName"]) runner.AddActivityLogTrigger(stackOutputs["UserPoolId"], stackOutputs["ActivityLogFunctionArn"]) runner.SignInUser(stackOutputs["UserPoolClientId"], userName, password) runner.helper.ListRecentLogEvents(stackOutputs["ActivityLogFunction"]) runner.GetKnownUserLastLogin(stackOutputs["TableName"], userName) runner.resources.Cleanup() log.Println(strings.Repeat("-", 88)) log.Println("Thanks for watching!") log.Println(strings.Repeat("-", 88)) }

Lambda 関数を使用してPostAuthenticationトリガーを処理します。

const TABLE_NAME = "TABLE_NAME" // LoginInfo defines structured login data that can be marshalled to a DynamoDB format. type LoginInfo struct { UserPoolId string `dynamodbav:"UserPoolId"` ClientId string `dynamodbav:"ClientId"` Time string `dynamodbav:"Time"` } // UserInfo defines structured user data that can be marshalled to a DynamoDB format. type UserInfo struct { UserName string `dynamodbav:"UserName"` UserEmail string `dynamodbav:"UserEmail"` LastLogin LoginInfo `dynamodbav:"LastLogin"` } // GetKey marshals the user email value to a DynamoDB key format. func (user UserInfo) GetKey() map[string]dynamodbtypes.AttributeValue { userEmail, err := attributevalue.Marshal(user.UserEmail) if err != nil { panic(err) } return map[string]dynamodbtypes.AttributeValue{"UserEmail": userEmail} } type handler struct { dynamoClient *dynamodb.Client } // HandleRequest handles the PostAuthentication event by writing custom data to the logs and // to an Amazon DynamoDB table. func (h *handler) HandleRequest(ctx context.Context, event events.CognitoEventUserPoolsPostAuthentication) (events.CognitoEventUserPoolsPostAuthentication, error) { log.Printf("Received post authentication trigger from %v for user '%v'", event.TriggerSource, event.UserName) tableName := os.Getenv(TABLE_NAME) user := UserInfo{ UserName: event.UserName, UserEmail: event.Request.UserAttributes["email"], LastLogin: LoginInfo{ UserPoolId: event.UserPoolID, ClientId: event.CallerContext.ClientID, Time: time.Now().Format(time.UnixDate), }, } // Write to CloudWatch Logs. fmt.Printf("%#v", user) // Also write to an external system. This examples uses DynamoDB to demonstrate. userMap, err := attributevalue.MarshalMap(user) if err != nil { log.Printf("Couldn't marshal to DynamoDB map. Here's why: %v\n", err) } else if len(userMap) == 0 { log.Printf("User info marshaled to an empty map.") } else { _, err := h.dynamoClient.PutItem(ctx, &dynamodb.PutItemInput{ Item: userMap, TableName: aws.String(tableName), }) if err != nil { log.Printf("Couldn't write to DynamoDB. Here's why: %v\n", err) } else { log.Printf("Wrote user info to DynamoDB table %v.\n", tableName) } } return event, nil } func main() { sdkConfig, err := config.LoadDefaultConfig(context.TODO()) if err != nil { log.Panicln(err) } h := handler{ dynamoClient: dynamodb.NewFromConfig(sdkConfig), } lambda.Start(h.HandleRequest) }

一般的なタスクを実行する構造体を作成します。

// IScenarioHelper defines common functions used by the workflows in this example. type IScenarioHelper interface { Pause(secs int) GetStackOutputs(stackName string) (actions.StackOutputs, error) PopulateUserTable(tableName string) GetKnownUsers(tableName string) (actions.UserList, error) AddKnownUser(tableName string, user actions.User) ListRecentLogEvents(functionName string) } // ScenarioHelper contains AWS wrapper structs used by the workflows in this example. type ScenarioHelper struct { questioner demotools.IQuestioner dynamoActor *actions.DynamoActions cfnActor *actions.CloudFormationActions cwlActor *actions.CloudWatchLogsActions isTestRun bool } // NewScenarioHelper constructs a new scenario helper. func NewScenarioHelper(sdkConfig aws.Config, questioner demotools.IQuestioner) ScenarioHelper { scenario := ScenarioHelper{ questioner: questioner, dynamoActor: &actions.DynamoActions{DynamoClient: dynamodb.NewFromConfig(sdkConfig)}, cfnActor: &actions.CloudFormationActions{CfnClient: cloudformation.NewFromConfig(sdkConfig)}, cwlActor: &actions.CloudWatchLogsActions{CwlClient: cloudwatchlogs.NewFromConfig(sdkConfig)}, } return scenario } // Pause waits for the specified number of seconds. func (helper ScenarioHelper) Pause(secs int) { if !helper.isTestRun { time.Sleep(time.Duration(secs) * time.Second) } } // GetStackOutputs gets the outputs from the specified CloudFormation stack in a structured format. func (helper ScenarioHelper) GetStackOutputs(stackName string) (actions.StackOutputs, error) { return helper.cfnActor.GetOutputs(stackName), nil } // PopulateUserTable fills the known user table with example data. func (helper ScenarioHelper) PopulateUserTable(tableName string) { log.Printf("First, let's add some users to the DynamoDB %v table we'll use for this example.\n", tableName) err := helper.dynamoActor.PopulateTable(tableName) if err != nil { panic(err) } } // GetKnownUsers gets the users from the known users table in a structured format. func (helper ScenarioHelper) GetKnownUsers(tableName string) (actions.UserList, error) { knownUsers, err := helper.dynamoActor.Scan(tableName) if err != nil { log.Printf("Couldn't get known users from table %v. Here's why: %v\n", tableName, err) } return knownUsers, err } // AddKnownUser adds a user to the known users table. func (helper ScenarioHelper) AddKnownUser(tableName string, user actions.User) { log.Printf("Adding user '%v' with email '%v' to the DynamoDB known users table...\n", user.UserName, user.UserEmail) err := helper.dynamoActor.AddUser(tableName, user) if err != nil { panic(err) } } // ListRecentLogEvents gets the most recent log stream and events for the specified Lambda function and displays them. func (helper ScenarioHelper) ListRecentLogEvents(functionName string) { log.Println("Waiting a few seconds to let Lambda write to CloudWatch Logs...") helper.Pause(10) log.Println("Okay, let's check the logs to find what's happened recently with your Lambda function.") logStream, err := helper.cwlActor.GetLatestLogStream(functionName) if err != nil { panic(err) } log.Printf("Getting some recent events from log stream %v\n", *logStream.LogStreamName) events, err := helper.cwlActor.GetLogEvents(functionName, *logStream.LogStreamName, 10) if err != nil { panic(err) } for _, event := range events { log.Printf("\t%v", *event.Message) } log.Println(strings.Repeat("-", 88)) }

Amazon Cognito アクションをラップする構造体を作成します。

type CognitoActions struct { CognitoClient *cognitoidentityprovider.Client } // Trigger and TriggerInfo define typed data for updating an Amazon Cognito trigger. type Trigger int const ( PreSignUp Trigger = iota UserMigration PostAuthentication ) type TriggerInfo struct { Trigger Trigger HandlerArn *string } // UpdateTriggers adds or removes Lambda triggers for a user pool. When a trigger is specified with a `nil` value, // it is removed from the user pool. func (actor CognitoActions) UpdateTriggers(userPoolId string, triggers ...TriggerInfo) error { output, err := actor.CognitoClient.DescribeUserPool(context.TODO(), &cognitoidentityprovider.DescribeUserPoolInput{ UserPoolId: aws.String(userPoolId), }) if err != nil { log.Printf("Couldn't get info about user pool %v. Here's why: %v\n", userPoolId, err) return err } lambdaConfig := output.UserPool.LambdaConfig for _, trigger := range triggers { switch trigger.Trigger { case PreSignUp: lambdaConfig.PreSignUp = trigger.HandlerArn case UserMigration: lambdaConfig.UserMigration = trigger.HandlerArn case PostAuthentication: lambdaConfig.PostAuthentication = trigger.HandlerArn } } _, err = actor.CognitoClient.UpdateUserPool(context.TODO(), &cognitoidentityprovider.UpdateUserPoolInput{ UserPoolId: aws.String(userPoolId), LambdaConfig: lambdaConfig, }) if err != nil { log.Printf("Couldn't update user pool %v. Here's why: %v\n", userPoolId, err) } return err } // SignUp signs up a user with Amazon Cognito. func (actor CognitoActions) SignUp(clientId string, userName string, password string, userEmail string) (bool, error) { confirmed := false output, err := actor.CognitoClient.SignUp(context.TODO(), &cognitoidentityprovider.SignUpInput{ ClientId: aws.String(clientId), Password: aws.String(password), Username: aws.String(userName), UserAttributes: []types.AttributeType{ {Name: aws.String("email"), Value: aws.String(userEmail)}, }, }) if err != nil { var invalidPassword *types.InvalidPasswordException if errors.As(err, &invalidPassword) { log.Println(*invalidPassword.Message) } else { log.Printf("Couldn't sign up user %v. Here's why: %v\n", userName, err) } } else { confirmed = output.UserConfirmed } return confirmed, err } // SignIn signs in a user to Amazon Cognito using a username and password authentication flow. func (actor CognitoActions) SignIn(clientId string, userName string, password string) (*types.AuthenticationResultType, error) { var authResult *types.AuthenticationResultType output, err := actor.CognitoClient.InitiateAuth(context.TODO(), &cognitoidentityprovider.InitiateAuthInput{ AuthFlow: "USER_PASSWORD_AUTH", ClientId: aws.String(clientId), AuthParameters: map[string]string{"USERNAME": userName, "PASSWORD": password}, }) if err != nil { var resetRequired *types.PasswordResetRequiredException if errors.As(err, &resetRequired) { log.Println(*resetRequired.Message) } else { log.Printf("Couldn't sign in user %v. Here's why: %v\n", userName, err) } } else { authResult = output.AuthenticationResult } return authResult, err } // ForgotPassword starts a password recovery flow for a user. This flow typically sends a confirmation code // to the user's configured notification destination, such as email. func (actor CognitoActions) ForgotPassword(clientId string, userName string) (*types.CodeDeliveryDetailsType, error) { output, err := actor.CognitoClient.ForgotPassword(context.TODO(), &cognitoidentityprovider.ForgotPasswordInput{ ClientId: aws.String(clientId), Username: aws.String(userName), }) if err != nil { log.Printf("Couldn't start password reset for user '%v'. Here;s why: %v\n", userName, err) } return output.CodeDeliveryDetails, err } // ConfirmForgotPassword confirms a user with a confirmation code and a new password. func (actor CognitoActions) ConfirmForgotPassword(clientId string, code string, userName string, password string) error { _, err := actor.CognitoClient.ConfirmForgotPassword(context.TODO(), &cognitoidentityprovider.ConfirmForgotPasswordInput{ ClientId: aws.String(clientId), ConfirmationCode: aws.String(code), Password: aws.String(password), Username: aws.String(userName), }) if err != nil { var invalidPassword *types.InvalidPasswordException if errors.As(err, &invalidPassword) { log.Println(*invalidPassword.Message) } else { log.Printf("Couldn't confirm user %v. Here's why: %v", userName, err) } } return err } // DeleteUser removes a user from the user pool. func (actor CognitoActions) DeleteUser(userAccessToken string) error { _, err := actor.CognitoClient.DeleteUser(context.TODO(), &cognitoidentityprovider.DeleteUserInput{ AccessToken: aws.String(userAccessToken), }) if err != nil { log.Printf("Couldn't delete user. Here's why: %v\n", err) } return err } // AdminCreateUser uses administrator credentials to add a user to a user pool. This method leaves the user // in a state that requires they enter a new password next time they sign in. func (actor CognitoActions) AdminCreateUser(userPoolId string, userName string, userEmail string) error { _, err := actor.CognitoClient.AdminCreateUser(context.TODO(), &cognitoidentityprovider.AdminCreateUserInput{ UserPoolId: aws.String(userPoolId), Username: aws.String(userName), MessageAction: types.MessageActionTypeSuppress, UserAttributes: []types.AttributeType{{Name: aws.String("email"), Value: aws.String(userEmail)}}, }) if err != nil { var userExists *types.UsernameExistsException if errors.As(err, &userExists) { log.Printf("User %v already exists in the user pool.", userName) err = nil } else { log.Printf("Couldn't create user %v. Here's why: %v\n", userName, err) } } return err } // AdminSetUserPassword uses administrator credentials to set a password for a user without requiring a // temporary password. func (actor CognitoActions) AdminSetUserPassword(userPoolId string, userName string, password string) error { _, err := actor.CognitoClient.AdminSetUserPassword(context.TODO(), &cognitoidentityprovider.AdminSetUserPasswordInput{ Password: aws.String(password), UserPoolId: aws.String(userPoolId), Username: aws.String(userName), Permanent: true, }) if err != nil { var invalidPassword *types.InvalidPasswordException if errors.As(err, &invalidPassword) { log.Println(*invalidPassword.Message) } else { log.Printf("Couldn't set password for user %v. Here's why: %v\n", userName, err) } } return err }

DynamoDB アクションをラップする構造体を作成します。

// DynamoActions encapsulates the Amazon Simple Notification Service (Amazon SNS) actions // used in the examples. type DynamoActions struct { DynamoClient *dynamodb.Client } // User defines structured user data. type User struct { UserName string UserEmail string LastLogin *LoginInfo `dynamodbav:",omitempty"` } // LoginInfo defines structured custom login data. type LoginInfo struct { UserPoolId string ClientId string Time string } // UserList defines a list of users. type UserList struct { Users []User } // UserNameList returns the usernames contained in a UserList as a list of strings. func (users *UserList) UserNameList() []string { names := make([]string, len(users.Users)) for i := 0; i < len(users.Users); i++ { names[i] = users.Users[i].UserName } return names } // PopulateTable adds a set of test users to the table. func (actor DynamoActions) PopulateTable(tableName string) error { var err error var item map[string]types.AttributeValue var writeReqs []types.WriteRequest for i := 1; i < 4; i++ { item, err = attributevalue.MarshalMap(User{UserName: fmt.Sprintf("test_user_%v", i), UserEmail: fmt.Sprintf("test_email_%v@example.com", i)}) if err != nil { log.Printf("Couldn't marshall user into DynamoDB format. Here's why: %v\n", err) return err } writeReqs = append(writeReqs, types.WriteRequest{PutRequest: &types.PutRequest{Item: item}}) } _, err = actor.DynamoClient.BatchWriteItem(context.TODO(), &dynamodb.BatchWriteItemInput{ RequestItems: map[string][]types.WriteRequest{tableName: writeReqs}, }) if err != nil { log.Printf("Couldn't populate table %v with users. Here's why: %v\n", tableName, err) } return err } // Scan scans the table for all items. func (actor DynamoActions) Scan(tableName string) (UserList, error) { var userList UserList output, err := actor.DynamoClient.Scan(context.TODO(), &dynamodb.ScanInput{ TableName: aws.String(tableName), }) if err != nil { log.Printf("Couldn't scan table %v for items. Here's why: %v\n", tableName, err) } else { err = attributevalue.UnmarshalListOfMaps(output.Items, &userList.Users) if err != nil { log.Printf("Couldn't unmarshal items into users. Here's why: %v\n", err) } } return userList, err } // AddUser adds a user item to a table. func (actor DynamoActions) AddUser(tableName string, user User) error { userItem, err := attributevalue.MarshalMap(user) if err != nil { log.Printf("Couldn't marshall user to item. Here's why: %v\n", err) } _, err = actor.DynamoClient.PutItem(context.TODO(), &dynamodb.PutItemInput{ Item: userItem, TableName: aws.String(tableName), }) if err != nil { log.Printf("Couldn't put item in table %v. Here's why: %v", tableName, err) } return err }

CloudWatch Logs アクションをラップする構造体を作成します。

type CloudWatchLogsActions struct { CwlClient *cloudwatchlogs.Client } // GetLatestLogStream gets the most recent log stream for a Lambda function. func (actor CloudWatchLogsActions) GetLatestLogStream(functionName string) (types.LogStream, error) { var logStream types.LogStream logGroupName := fmt.Sprintf("/aws/lambda/%s", functionName) output, err := actor.CwlClient.DescribeLogStreams(context.TODO(), &cloudwatchlogs.DescribeLogStreamsInput{ Descending: aws.Bool(true), Limit: aws.Int32(1), LogGroupName: aws.String(logGroupName), OrderBy: types.OrderByLastEventTime, }) if err != nil { log.Printf("Couldn't get log streams for log group %v. Here's why: %v\n", logGroupName, err) } else { logStream = output.LogStreams[0] } return logStream, err } // GetLogEvents gets the most recent eventCount events from the specified log stream. func (actor CloudWatchLogsActions) GetLogEvents(functionName string, logStreamName string, eventCount int32) ( []types.OutputLogEvent, error) { var events []types.OutputLogEvent logGroupName := fmt.Sprintf("/aws/lambda/%s", functionName) output, err := actor.CwlClient.GetLogEvents(context.TODO(), &cloudwatchlogs.GetLogEventsInput{ LogStreamName: aws.String(logStreamName), Limit: aws.Int32(eventCount), LogGroupName: aws.String(logGroupName), }) if err != nil { log.Printf("Couldn't get log event for log stream %v. Here's why: %v\n", logStreamName, err) } else { events = output.Events } return events, err }

AWS CloudFormation アクションをラップする構造体を作成します。

// StackOutputs defines a map of outputs from a specific stack. type StackOutputs map[string]string type CloudFormationActions struct { CfnClient *cloudformation.Client } // GetOutputs gets the outputs from a CloudFormation stack and puts them into a structured format. func (actor CloudFormationActions) GetOutputs(stackName string) StackOutputs { output, err := actor.CfnClient.DescribeStacks(context.TODO(), &cloudformation.DescribeStacksInput{ StackName: aws.String(stackName), }) if err != nil || len(output.Stacks) == 0 { log.Panicf("Couldn't find a CloudFormation stack named %v. Here's why: %v\n", stackName, err) } stackOutputs := StackOutputs{} for _, out := range output.Stacks[0].Outputs { stackOutputs[*out.OutputKey] = *out.OutputValue } return stackOutputs }

リソースをクリーンアップします。

// Resources keeps track of AWS resources created during an example and handles // cleanup when the example finishes. type Resources struct { userPoolId string userAccessTokens []string triggers []actions.Trigger cognitoActor *actions.CognitoActions questioner demotools.IQuestioner } func (resources *Resources) init(cognitoActor *actions.CognitoActions, questioner demotools.IQuestioner) { resources.userAccessTokens = []string{} resources.triggers = []actions.Trigger{} resources.cognitoActor = cognitoActor resources.questioner = questioner } // Cleanup deletes all AWS resources created during an example. func (resources *Resources) Cleanup() { defer func() { if r := recover(); r != nil { log.Printf("Something went wrong during cleanup.\n%v\n", r) log.Println("Use the AWS Management Console to remove any remaining resources \n" + "that were created for this scenario.") } }() wantDelete := resources.questioner.AskBool("Do you want to remove all of the AWS resources that were created "+ "during this demo (y/n)?", "y") if wantDelete { for _, accessToken := range resources.userAccessTokens { err := resources.cognitoActor.DeleteUser(accessToken) if err != nil { log.Println("Couldn't delete user during cleanup.") panic(err) } log.Println("Deleted user.") } triggerList := make([]actions.TriggerInfo, len(resources.triggers)) for i := 0; i < len(resources.triggers); i++ { triggerList[i] = actions.TriggerInfo{Trigger: resources.triggers[i], HandlerArn: nil} } err := resources.cognitoActor.UpdateTriggers(resources.userPoolId, triggerList...) if err != nil { log.Println("Couldn't update Cognito triggers during cleanup.") panic(err) } log.Println("Removed Cognito triggers from user pool.") } else { log.Println("Be sure to remove resources when you're done with them to avoid unexpected charges!") } }