You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NodeJS调用AWS STS AssumeRole成功,Go同凭证报403错误求助

AWS STS AssumeRole 403错误:Go代码失败但NodeJS成功

我分别用Golang和NodeJS编写代码,使用同一组accessKey、secretKey和roleARN获取AWS临时凭证。NodeJS代码能成功获取,但Go代码抛出如下权限错误:

operation error STS: AssumeRole, https response error StatusCode: 403, RequestID: ebccfbf8-abed-4490-83ce-730d87d131, api error AccessDenied: User: arn:aws:iam::<accountID>:user/sts-user-1234 is not authorized to perform: sts:AssumeRole on resource: arn:aws:iam::<accountID>:role/sts-role-123

Go代码相关

使用的包版本

github.com/aws/aws-sdk-go-v2 v1.20.0 github.com/aws/aws-sdk-go-v2/config v1.18.29 github.com/aws/aws-sdk-go-v2/service/sts v1.20.0

Go代码

package main

import (
    "context"
    "errors"
    "fmt"
    "net/http"
    "os"

    "github.com/aws/aws-sdk-go-v2/aws"
    "github.com/aws/aws-sdk-go-v2/config"
    "github.com/aws/aws-sdk-go-v2/credentials"
    "github.com/aws/aws-sdk-go-v2/service/sts"
)

// AWSProvider ...
type AWSProvider struct{}

// NewAWSProvider ...
// var NewAWSProvider Connection = &AWSProvider{}

var (
    defaultRegion      = "us-east-1"
    defaultSessionName = "MCMP"
)

// ConnectionValidation ...
type ConnectionValidation struct {
    ConnectionID  string   `json:"connectionId" bson:"connectionId"`
    VaultConfigID string   `json:"vaultConfigId,omitempty"`
    Provider      Provider `json:"provider,omitempty" bson:"provider"`
    Reference     string   `json:"reference,omitempty" bson:"reference"`
}

type Provider struct {
    Type        string                 `json:"type" bson:"type" validate:"required"`
    ConfigData  map[string]interface{} `json:"configData,omitempty" bson:"configData,omitempty"`
    Credentials []Fields               `json:"credentials,omitempty" bson:"credentials,omitempty"`
}

type Fields struct {
    Key   string `json:"key"`
    Value string `json:"value"`
}

// Validate ...
func Validate(connection *ConnectionValidation) (err error) {
    accessKey := "<accessKey>"
    secretKey := "<secretKey>"

    configData := connection.Provider.ConfigData
    if configData["delegatedAccess"] != nil {
        delegatedAccess, ok := configData["delegatedAccess"].(string)
        if !ok || delegatedAccess == "" {
            err = errors.New("invalid delegatedAccess")
            return
        }
        err = validateDelegatedAccess(connection, accessKey, secretKey, delegatedAccess)
        return
    }

    err = validateAsset(accessKey, secretKey, defaultRegion)
    return
}

// checkAndAddProxy ...
func checkAndAddProxy(config aws.Config) aws.Config {
    if os.Getenv("https_proxy") != "" {
        httpclient := &http.Client{
            Transport: &http.Transport{
                Proxy: http.ProxyFromEnvironment,
            },
        }
        config.HTTPClient = httpclient
    }
    return config
}

func validateDelegatedAccess(connection *ConnectionValidation, accessKey, secretKey, delegatedAccess string) (err error) {
    config, err := config.LoadDefaultConfig(context.TODO(), config.WithRegion(defaultRegion))
    if err != nil {
        panic("configuration error validateDelegatedAccess, " + err.Error())
    }
    config = checkAndAddProxy(config)
    config.Region = defaultRegion

    config.Credentials = aws.NewCredentialsCache(credentials.NewStaticCredentialsProvider(accessKey, secretKey, ""))

    client := sts.NewFromConfig(config)

    params := &sts.AssumeRoleInput{
        RoleArn:         &delegatedAccess,
        RoleSessionName: &defaultSessionName,
    }

    configData := connection.Provider.ConfigData
    if configData["externalID"] != nil {
        externalID, ok := configData["externalID"].(string)
        if !ok || externalID == "" {
            err = errors.New("invalid externalID")
            return
        }
        params.ExternalId = &externalID
    }

    _, err = client.AssumeRole(context.TODO(), params)
    return
}

func validateAsset(accessKey, secretKey, region string) (err error) {
    config := *aws.NewConfig()
    config.Region = defaultRegion
    config.Credentials = aws.NewCredentialsCache(credentials.NewStaticCredentialsProvider(accessKey, secretKey, ""))
    config = checkAndAddProxy(config)

    client := sts.NewFromConfig(config)

    input := &sts.GetCallerIdentityInput{}
    _, err = client.GetCallerIdentity(context.TODO(), input)
    if err != nil {
        return err
    }
    return
}

func main() {
    fmt.Println("---validate aws creds---")
    conn := ConnectionValidation{
        ConnectionID: "id",
        Provider: Provider{Type: "aws",
            ConfigData: map[string]interface{}{"accountNumber": "<accountNumber>",
                "delegatedAccess": "<ARN>",
                "externalId":      "12345"},
        },
    }
    err := Validate(&conn)
    if err != nil {
        fmt.Printf("\n --- error validate aws creds---%+v", err)
    } else {
        fmt.Println("validate creds success")
    }

}

NodeJS代码相关

使用的包版本

"aws-sdk": "^2.1429.0"

NodeJS代码

var AWSClient = require('aws-sdk');
var proxy = require('proxy-agent');

var checkForProxy = function () {
  if (process.env.https_proxy !== undefined) {
    console.log("Configuring AWS client to use https proxy");
    AWSClient.config.update({
      httpOptions: { agent: proxy(process.env.https_proxy) }
    });
  }
}

async function getTempCredentials(result) {
  console.log('-- Inside credential-validator-service/getTempCredentials... --');
  try {
    return new Promise(function (resolve, reject) {
      if (result['delegatedAccess'] && result['accessKey'] && result['secretKey']) {
        AWSClient.config.update({
          accessKeyId: result['accessKey'],
          secretAccessKey: result['secretKey'],
          region:"us-east-1"
        });
        checkForProxy()
        console.log("AWSClient config-----")
        console.log(AWSClient.config)
        var sts = new AWSClient.STS();
        var params = {
          RoleArn: result['delegatedAccess'],
          RoleSessionName: "MCMP"
        };
        if (result['externalId']) {
          console.log("Found externalId in payload, validating ARN with externalId")
          params['ExternalId'] = result['externalId']
        }
        sts.assumeRole(params, function (err, result) {
          if (err) {
            console.log("Error occured " + JSON.stringify(err));
            reject(err);
          } else {
            console.log("Temporary credential retrieved successfully");
            resolve({
              "message": "Delegated Credentials fetched successfully",
              "delegatedcredentials": result['Credentials'],
              "translateCode": "CO200_FETCH_SUCCESS",
              "translateParameters": [],
              "statusCode": 200
            });
          }
        });
      } else {
        reject({
          "message": "Required credential details not found to fetch role, please provide arn, accessKey and secretKey",
          "translateCode": "CO400_FETCH_FAIL",
          "translateParameters": [],
          "statusCode": 400
        });
      }
    });
  } catch (error) {
    console.log.error("error while calling assume role of aws : " + JSON.stringify(error));
    return {
      "message": "System Failure. Due to: " + error.message,
      "translateCode": "CO500_ERR",
      "translateParameters": [error.message],
      "statusCode": 500
    }
  }
}

const checkDelegateAndUpdate = (body, callback) => {
  if (body.credentials.delegatedAccess) {
    const payload = {
      accessKey: body.credentials.passwordFields.accessKey,
      secretKey: body.credentials.passwordFields.secretKey,
      delegatedAccess: body.credentials.delegatedAccess,
      externalId: body.credentials.externalId
    };
    getTempCredentials(payload).then(({
      delegatedcredentials
    }) => {
      AWSClient.config.update({
        accessKeyId: delegatedcredentials.AccessKeyId,
        secretAccessKey: delegatedcredentials.SecretAccessKey,
        sessionToken: delegatedcredentials.SessionToken
      });
      callback(null, "Success");
    }).catch(err => {
      console.log("Error occured while fetching temporary credentials ", err.message);
      callback(err);
    });
  } else {
    AWSClient.config.update({
      accessKeyId: body.credentials.passwordFields.accessKey,
      secretAccessKey: body.credentials.passwordFields.secretKey
    });
    callback(null, "Success");
  }
}

var testAccount = function (asset_payload, callback) {

  if (!asset_payload.credentials.passwordFields.accessKey ||
    !asset_payload.credentials.passwordFields.secretKey) {
    return callback(Error, null);
  } else {
    checkDelegateAndUpdate(asset_payload, (err, _res) => {
      if (err) {
        return callback(err, null);
      } else {
        AWSClient.config.update({
          accessKeyId: asset_payload.credentials.passwordFields.accessKey,
          secretAccessKey: asset_payload.credentials.passwordFields.secretKey
        });

        checkForProxy()
        var sts = new AWSClient.STS();
        sts.getCallerIdentity({}, function (err, response) {
          if (err) {
            return callback(err, null);
          } else {
            return callback(null, response);
          }
        });
      }
    });
  }
};

var requestPayload = {
    "basicInfo": {
        "accountName": "camaws",
        "serviceProviderType": "aws",
        "serviceProviderCode": "aws",
        "isActive": "Active",
        "accountType": "subaccount",
        "userType": "asset"
    },
    "advancedInfo": {
        "accountNumber": "<accountumber>"
    },
    "credentials": {
        "credentialName": "awscred",
        "purpose": ["assetIngestion"],
        "status": true,
        "externalId": "12345",
        "delegatedAccess": "<ARN>",
        "passwordFields": {
            "accessKey": "<accessKey>",
            "secretKey": "<secretKey>",
            "additionalInfo": ""
        }
    }
}


testAccount(requestPayload, function (err, result) {
    if (err) {
        console.log(err)
    }else{
        console.log("success*********")
        console.log(result)
    }
});

内容的提问来源于stack exchange,提问作者Neha

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 08:36:02