AWSTemplateFormatVersion: '2010-09-09' Description: '' Resources: IamPasswordPolicy: Type: 'Custom::PasswordPolicy' Properties: HardExpiry: false AllowUsersToChangePassword: true MaxPasswordAge: 90 MinimumPasswordLength: 14 PasswordReusePrevention: 6 RequireLowercaseCharacters: true RequireNumbers: true RequireSymbols: true RequireUppercaseCharacters: true ServiceToken: 'Fn::GetAtt': - IamPasswordPolicyLambda - Arn IamPasswordPolicyLambdaRole: Type: 'AWS::IAM::Role' Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: lambda.amazonaws.com Action: - 'sts:AssumeRole' Path: / ManagedPolicyArns: - 'arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole' Policies: - PolicyName: iam PolicyDocument: Statement: - Effect: Allow Action: - 'iam:UpdateAccountPasswordPolicy' - 'iam:DeleteAccountPasswordPolicy' Resource: '*' IamPasswordPolicyLambda: Type: 'AWS::Lambda::Function' Properties: Code: ZipFile: >- 'use strict'; const AWS = require('aws-sdk'); const response = require('cfn-response'); const iam = new AWS.IAM({apiVersion: '2010-05-08'}); exports.handler = (event, context, cb) => { console.log(`Invoke: ${JSON.stringify(event)}`); const done = (err) => { if (err) { console.log(`Error: ${JSON.stringify(err)}`); response.send(event, context, response.FAILED, {}, event.PhysicalResourceId); } else { response.send(event, context, response.SUCCESS, {}, event.PhysicalResourceId ); } }; if (event.RequestType === 'Delete') { iam.deleteAccountPasswordPolicy({}, done); } else if (event.RequestType === 'Create' || event.RequestType === 'Update') { let params = { AllowUsersToChangePassword: event.ResourceProperties.AllowUsersToChangePassword === 'true', HardExpiry: event.ResourceProperties.HardExpiry === 'true', MinimumPasswordLength: parseInt(event.ResourceProperties.MinimumPasswordLength, 10), RequireLowercaseCharacters: event.ResourceProperties.RequireLowercaseCharacters === 'true', RequireNumbers: event.ResourceProperties.RequireNumbers === 'true', RequireSymbols: event.ResourceProperties.RequireSymbols === 'true', RequireUppercaseCharacters: event.ResourceProperties.RequireUppercaseCharacters === 'true', }; if (parseInt(event.ResourceProperties.MaxPasswordAge, 10) > 0) { params.MaxPasswordAge = parseInt(event.ResourceProperties.MaxPasswordAge, 10); } if (parseInt(event.ResourceProperties.PasswordReusePrevention, 10) > 0) { params.PasswordReusePrevention = parseInt(event.ResourceProperties.PasswordReusePrevention, 10); } iam.updateAccountPasswordPolicy(params, done); } else { cb(new Error(`unsupported RequestType: ${event.RequestType}`)); } }; Handler: index.handler MemorySize: 128 Role: 'Fn::GetAtt': - IamPasswordPolicyLambdaRole - Arn Runtime: nodejs12.x Timeout: 60 Parameters: {} Metadata: {} Conditions: {}