使用Node.js Lambda自动化AWS Organizations创建账户无响应排障求助
问题描述
使用Node.js 16x + AWS SDK v3编写Lambda,通过Serverless框架部署,自动化AWS Organizations内的账户创建流程。执行到await client.send(command)后无后续日志输出,既没有响应结果也没有错误信息,但使用AWS CLI执行相同操作可成功返回CreateAccountStatus。
Serverless.yml配置
functions: fnPostOrganizations: name: fnPostOrganizations handler: src/Organizations/fnPostOrganizations.fnPostOrganizations events: - http: path: /organizations/create_account method: POST request: parameters: querystrings: name: true token: false orgUnit: true memorySize: 256 timeout: 900 logRetentionInDays: 1 iamRoleStatementsName: fnPostOrganizations-${self:provider.stage} iamRoleStatements: - Effect: 'Allow' Action: - 'organizations:*' Resource: '*'
Lambda核心代码
'use strict' const { OrganizationsClient, CreateAccountCommand } = require("@aws-sdk/client-organizations") const client = new OrganizationsClient({ region: "us-east-1" }); console.log('🚀 client', client) const postOrganizationsCreateAccount = async () => { try { console.log('🚀 START postOrganizationsCreateAccount') const params = { AccountName: 'testIg', Email: `awsTestIg@test.com`, IamUserAccessToBilling: 'DENY' } console.log('🚀 params', params) const command = new CreateAccountCommand(params) console.log('🚀 command', command) const createAccountResponse = await client.send(command) console.log('🚀 createAccountResponse', createAccountResponse) return createAccountResponse } catch (error) { console.log('🚀 postOrganizationsCreateAccount - error.stack:', error.stack) return error.stack } }
CloudWatch日志输出
2022-10-16T17:14:50.989Z undefined INFO 🚀 client OrganizationsClient { middlewareStack: { add: [Function: add], addRelativeTo: [Function: addRelativeTo], clone: [Function: clone], use: [Function: use], remove: [Function: remove], removeByTag: [Function: removeByTag], concat: [Function: concat], applyToStack: [Function: cloneTo], identify: [Function: identify], resolve: [Function: resolve] }, config: { apiVersion: '2016-11-28', disableHostPrefix: false, logger: {}, regionInfoProvider: [AsyncFunction: defaultRegionInfoProvider], serviceId: 'Organizations', urlParser: [Function: parseUrl], region: [AsyncFunction: region], runtime: 'node', defaultsMode: [AsyncFunction (anonymous)], base64Decoder: [Function: fromBase64], base64Encoder: [Function: toBase64], bodyLengthChecker: [Function: calculateBodyLength], credentialDefaultProvider: [Function (anonymous)], defaultUserAgentProvider: [AsyncFunction (anonymous)], maxAttempts: [AsyncFunction (anonymous)], requestHandler: NodeHttpHandler { metadata: [Object], configProvider: [Promise] }, retryMode: [AsyncFunction (anonymous)], sha256: [Function: bound Hash], streamCollector: [Function: streamCollector], useDualstackEndpoint: [AsyncFunction (anonymous)], useFipsEndpoint: [AsyncFunction (anonymous)], utf8Decoder: [Function: fromUtf8], utf8Encoder: [Function: toUtf8], tls: true, endpoint: [Function (anonymous)], isCustomEndpoint: false, retryStrategy: [AsyncFunction: retryStrategy], systemClockOffset: 0, signingEscapePath: true, credentials: [AsyncFunction (anonymous)], signer: [Function: signer], customUserAgent: undefined } } 2022-10-16T17:14:50.995Z 91b515e5-aa3c-4eb1-a6ba-7d12fd0beef5 INFO 🚀 START postOrganizationsCreateAccount 2022-10-16T17:14:50.995Z 91b515e5-aa3c-4eb1-a6ba-7d12fd0beef5 INFO 🚀 params { AccountName: 'testIg', Email: 'awsTestIg@test.com', IamUserAccessToBilling: 'DENY' } 2022-10-16T17:14:50.996Z 91b515e5-aa3c-4eb1-a6ba-7d12fd0beef5 INFO 🚀 command CreateAccountCommand { middlewareStack: { add: [Function: add], addRelativeTo: [Function: addRelativeTo], clone: [Function: clone], use: [Function: use], remove: [Function: remove], removeByTag: [Function: removeByTag], concat: [Function: concat], applyToStack: [Function: cloneTo], identify: [Function: identify], resolve: [Function: resolve] }, input: { AccountName: 'testIg', Email: 'awsTestIg@test.com', IamUserAccessToBilling: 'DENY' } } END RequestId: 91b515e5-aa3c-4eb1-a6ba-7d12fd0beef5 REPORT RequestId: 91b515e5-aa3c-4eb1-a6ba-7d12fd0beef5 Duration: 145.74 ms Billed Duration: 146 ms Memory Size: 256 MB Max Memory Used: 82 MB Init Duration: 414.12 ms
AWS CLI测试结果
执行命令:
aws organizations create-account --email testIgn@example.com --account-name "testIgName" --iam-user-access-to-billing "DENY"
返回结果:
{ "CreateAccountStatus": { "Id": "car-b4be21e04bfwert6wdgf", "AccountName": "testIgName", "State": "IN_PROGRESS", "RequestedTimestamp": "2022-10-14T15:59:26.737000-04:00" } }
排查思路
检查Lambda Handler的异步调用逻辑:确认入口函数
fnPostOrganizations是否正确等待postOrganizationsCreateAccount执行完成。如果handler未返回异步函数的Promise,Lambda会提前终止进程,导致client.send(command)的请求还未完成就被中断。示例修正:exports.fnPostOrganizations = async (event) => { const result = await postOrganizationsCreateAccount(); return { statusCode: 200, body: JSON.stringify(result) }; }完善错误日志捕获:在catch块中打印完整错误信息,而非仅stack,避免遗漏关键错误细节:
catch (error) { console.error('Create account error:', JSON.stringify(error, Object.getOwnPropertyNames(error))); return error.stack; }验证SDK客户端配置:尽管指定了
us-east-1(Organizations服务的唯一有效区域),可显式配置凭证链或添加请求超时,排查是否存在网络或凭证隐性问题:const { NodeHttpHandler } = require("@aws-sdk/node-http-handler"); const client = new OrganizationsClient({ region: "us-east-1", requestHandler: new NodeHttpHandler({ timeout: 30000 // 设置30秒超时 }) });检查Lambda网络环境:如果Lambda部署在VPC内,需确保VPC配置了NAT网关或Organizations的VPC端点,允许Lambda访问AWS公网服务。同时确认主账户未达到Organizations账户创建配额。
本地模拟测试:使用
serverless invoke local命令在本地运行Lambda,直接查看执行过程中的错误或响应,排除部署环境的影响。
内容的提问来源于stack exchange,提问作者IgorAlves

