This is a very weird problem, I am trying to assme a role and then get signinToken by nodejs through lambda function.
If I use a IAM user's ak/sk to assume the role (arn:aws:iam::432127183xxx:role/ssm-test) to get Credentials, and then use this Credentials to get signinToken, it works fine.
But is I use lambda role to assume role (arn:aws:iam::432127183xxx:role/ssm-test) to get Credentials, and then use this Credentials to get signinToken, it works failed. Got below error response from "https://ap-southeast-1.signin.aws.amazon.com/federation" get request:
"code":"ERR_BAD_REQUEST","status":400
Below is code
Successful code:
const axios = require('axios').default;
var AWS = require('aws-sdk');
exports.handler = async (event) => {
const { accessKeyId, secretAccessKey, sessionToken } = await getCredentialsForRole();
await generateSigninSSMConsoleLink(accessKeyId, secretAccessKey, sessionToken);
};
async function getCredentialsForRole() {
const stsEndpoint = 'https://sts.ap-southeast-1.amazonaws.com';
AWS.config.update(
{
stsRegionalEndpoints: 'regional',
region: 'ap-southeast-1',
maxRetries: 6,
retryDelayOptions: { base: 1000 },
accessKeyId: 'xxx', //accessKeyId and secretAccessKey is my IAM user AK/SK
secretAccessKey: 'xxx',
});
const sts = new AWS.STS({ apiVersion: '2011-06-15', endpoint: stsEndpoint });
const params = {
RoleArn: 'arn:aws:iam::432127183xxx:role/ssm-test',
RoleSessionName: 'test',
};
const { Credentials: creds } = await sts.assumeRole(params).promise();
const { AccessKeyId: accessKeyId, SecretAccessKey: secretAccessKey, SessionToken: sessionToken } = creds;
return { accessKeyId, secretAccessKey, sessionToken };
}
async function generateSigninSSMConsoleLink(accessKeyId, secretAccessKey, sessionToken) {
const session = {'sessionId': accessKeyId,
'sessionKey': secretAccessKey,
'sessionToken': sessionToken}
const params={'Action': 'getSigninToken',
'SessionDuration': 43200,
'Session': session};
const getSigninTokenURL = `https://signin.aws.amazon.com/federation`;
const response = await axios.get(getSigninTokenURL, {params});
const signinToken = response.data.SigninToken;
return signinToken
}
Below is code failed code:
const axios = require('axios').default;
var AWS = require('aws-sdk');
exports.handler = async (event) => {
const { accessKeyId, secretAccessKey, sessionToken } = await getCredentialsForRole();
await generateSigninSSMConsoleLink(accessKeyId, secretAccessKey, sessionToken);
};
async function getCredentialsForRole() {
const stsEndpoint = 'https://sts.ap-southeast-1.amazonaws.com';
AWS.config.update(
{
stsRegionalEndpoints: 'regional',
region: 'ap-southeast-1',
maxRetries: 6,
retryDelayOptions: { base: 1000 },
});
const sts = new AWS.STS({ apiVersion: '2011-06-15', endpoint: stsEndpoint });
const params = {
RoleArn: 'arn:aws:iam::432127183xxx:role/ssm-test',
RoleSessionName: 'test',
};
const { Credentials: creds } = await sts.assumeRole(params).promise();
const { AccessKeyId: accessKeyId, SecretAccessKey: secretAccessKey, SessionToken: sessionToken } = creds;
return { accessKeyId, secretAccessKey, sessionToken };
}
async function generateSigninSSMConsoleLink(accessKeyId, secretAccessKey, sessionToken) {
const session = {'sessionId': accessKeyId,
'sessionKey': secretAccessKey,
'sessionToken': sessionToken}
const params={'Action': 'getSigninToken',
'SessionDuration': 43200,
'Session': session};
const getSigninTokenURL = `https://signin.aws.amazon.com/federation`;
const response = await axios.get(getSigninTokenURL, {params});
const signinToken = response.data.SigninToken;
return signinToken
}
only difference between successful code and failed code is:
accessKeyId: 'xxx', //accessKeyId and secretAccessKey is my IAM user AK/SK
secretAccessKey: 'xxx',
As I mentioned before, if I user a IAM user to assume role, then can get signintoken
if I use lambda role to assume role, then cannot get signinToken.
Who can tell what's wrong?
Related
I am trying to call Amazon connect SDK Javascript V3 via lambda and my amazon connect instance is in another account. I am using sts assume role for cross-account access but i am having an error on resource not found. I am attaching my code so someone could help me. Thanks.
let { ConnectClient, SearchUsersCommand } = require("#aws-sdk/client-connect");
let { STSClient, AssumeRoleCommand } = require("#aws-sdk/client-sts");
let stsClient = new STSClient({ region: "eu-central-1" });
exports.handler = async function(event, context, callback) {
let params;
var stsParams = {
RoleArn: "arn:aws:iam::xxxxxxxx:role/Cross-Account-Role",
DurationSeconds: 1200,
RoleSessionName: "RoleSessionName" // any string
};
let stsCommand = new AssumeRoleCommand(stsParams);
const stsResp = await stsClient.send(stsCommand);
console.log({ stsResp });
let client = new ConnectClient({
region: "eu-central-1",
accessKeyId: stsResp.Credentials.AccessKeyId,
secretAccessKey: stsResp.Credentials.SecretAccessKey,
sessionToken: stsResp.Credentials.SessionToken,
})
// let client = await new ConnectClient(credentials);
console.log({ client });
params = {
InstanceId: "xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx",
MaxResults: 100
};
const command = new SearchUsersCommand(params);
console.log({command});
const resp = await client.send(command);
console.log({resp});
console.log("Users list", resp);
}
var stsParams = {
RoleArn: Role,
DurationSeconds: 1200,
RoleSessionName: RoleSessionName // any string
};
let stsCommand = new AssumeRoleCommand(stsParams);
const stsResp = await stsClient.send(stsCommand);
console.log({ stsResp });
client = new ConnectClient({
region: Region,
credentials: {
accessKeyId: stsResp.Credentials.AccessKeyId,
secretAccessKey: stsResp.Credentials.SecretAccessKey,
sessionToken: stsResp.Credentials.SessionToken,
}
})
I am trying to implement fleet provisioning in AWS Lambda function. As a starting point, I have this code:
'use strict';
var AWS = require('aws-sdk');
var iot = new AWS.Iot({
endpoint: 'apiendpoint',
accessKeyId: "AAAABBBBBCCCCDDDDD",
secretAccessKey: "AAAAABBBBCCCDD/1234122311222",
region: 'ap-south-1'
});
exports.handler = async (event, context) => {
var params = {
setAsActive: true
};
return {
statusCode: 200,
body:JSON.stringify(await createCertAndKey(params))
}
}
const createCertAndKey = async (params) => {
return new Promise((resolve, reject) => {
iot.createKeysAndCertificate(params, function(err, data){
if(err){
console.log(err);
reject(err)
}
else{
console.log("success?");
resolve(data)
}
})
})
}
I get a ResourceNotFound exception for calling createKeysAndCertificate. I also tried calling other functions of iot, but it gives the same exception.
What am I doing wrong here?
endpoint passed when intialzing an object should be generic AWS service in format https://{service}.{region}.amazonaws.com. we don't need to pass it, AWS will assume based on region and object we are initializing.
var iot = new AWS.Iot({
endpoint: 'iot.ap-south-1.amazonaws.com',
accessKeyId: "AAAABBBBBCCCCDDDDD",
secretAccessKey: "AAAAABBBBCCCDD/1234122311222",
region: 'ap-south-1'
});
I am trying to access cross-account API in AWS using the assumed role. The roles are configured correctly.
I am able to invoke API for the first and after that till the session duration, I am getting something like the following error. I am not sure how to handle this to make every request success. Please help.
Error: AccessDenied: User: arn:aws:sts::xxxxxxxxxx:assumed-role is not authorized to perform: sts:AssumeRole on resource: arn:aws:iam::xxxxx:role/assume-role
const AWS = require('aws-sdk')
var aws4 = require('aws4');
const REGION = process.env.REGION || 'eu-west-1';
const ASSUME_ROLE_ARN = process.env.ASSUME_ROLE_ARN || '';
const API_ID_PARAMETER = process.env.EXT_API_ID_PARAMETER || '/test/gl/module/dev/testapi';
exports.handler = async(event) => {
console.log('received event')
console.log('ASSUME_ROLE_ARN:' + ASSUME_ROLE_ARN);
console.log('API_ID_PARAMETER:' + EXT_API_ID_PARAMETER);
var sts = new AWS.STS({
region: REGION
});
console.log('sts success')
const getCrossAccountCredentials = async() => {
return new Promise((resolve, reject) => {
const timestamp = (new Date()).getTime();
const params = {
RoleArn: 'arn:aws:iam::XXXXXXXXXXX:role/assume-role',
RoleSessionName: `be-descriptibe-here-${timestamp}`,
DurationSeconds: 3600
};
console.log('RoleSessionName : ' + params.RoleSessionName)
sts.assumeRole(params, (err, data) => {
if (err)
reject(err);
else {
resolve({
accessKeyId: data.Credentials.AccessKeyId,
secretAccessKey: data.Credentials.SecretAccessKey,
sessionToken: data.Credentials.SessionToken,
});
}
});
});
}
try {
const tempdata = await getCrossAccountCredentials();
var data = JSON.parse(JSON.stringify(tempdata));
console.log(data);
console.log(data.accessKeyId);
console.log(data.secretAccessKey);
AWS.config.update({
accessKeyId: data.accessKeyId,
secretAccessKey: data.secretAccessKey,
sessionToken: data.sessionToken
});
const creds = {
accessKeyId: data.accessKeyId,
secretAccessKey: data.secretAccessKey,
sessionToken: data.sessionToken
};
console.log('AWS.SSM start')
var ssm = new AWS.SSM({
apiVersion: '2014-11-06',
region: REGION,
credentials: creds
});
console.log('AWS.SSM end')
const {
Parameter
} = await ssm
.getParameter({
Name: EXT_API_ID_PARAMETER
})
.promise();
console.log(Parameter.Value)
let request = {
host: `${Parameter.Value}.execute-api.eu-west-1.amazonaws.com`,
method: 'GET',
url: `https://${Parameter.Value}.execute-api.eu-west-1.amazonaws.com/dev/test/1`,
path: '/dev/test/1'
};
let signedRequest = aws4.sign(request, creds);
delete signedRequest.headers['Host'];
delete signedRequest.headers['Content-Length'];
const res = await axios(signedRequest);
console.log('Data:', res.data);
} catch (err) {
console.log('Error:', err);
}
};
I wrote this lambda function for creating new s3 bucket. I got success response, but there is no bucket created:
//Creating new s3 bucket
var AWS = require('aws-sdk');
AWS.config.update({
region: '',
accessKeyId: '',
secretAccessKey: ''
});
var s3 = new AWS.S3();
var bucketName = 'sample_bucket';
var keyName = 'sample_text.txt';
exports.handler = function uploadToS3(event, context, callback) {
s3.createBucket({Bucket: bucketName}, function() {
var params = {
Bucket: bucketName,
Key: keyName,
Body: 'Hello World!'
};
s3.putObject(params, function(err, data) {
if (err)
console.log(err);
else
console.log("Successfully uploaded data to " + bucketName);
});
});
callback(null,{ result : 'SUCCESS'});
};
Is there any problem in the code or do I have to provide some special access to
IAM user? I provided programmatic access to the IAM user.
Thanks!
These are my first steps in AWS in general and Cognito specifically. So please bear with me as I'm a bit confused by all the concepts and documention is not very easy to follow.
So I set up 3 lambda functions, one that creates a user, one that confirms a user and a last one that is supposed to authenticate the user.
The first 2 work fine, my user is created an confirmed. Now I'm stuck with the 3rd one which is supposed to return a token to be used in APIG, where I've set up a simple endpoint with my cognito authorizer.
Every token I get back returns Unauthorized when tested in the APIG/Authorizers/Cognito Pool Authorizers section.
My 'sign in' code is the following:
const AWS = require('aws-sdk');
exports.handler = (event, context, callback) => {
AWS.config.apiVersions = {
cognitoidentityserviceprovider: '2016-04-18'
};
AWS.config.region = 'us-east-1'; // Region
/*AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'MY_IDENTITY_POOL_ID',
});*/
var identityId = null;
var params = {
IdentityPoolId: 'MY_IDENTITY_POOL_ID',
IdentityId: identityId,
Logins: {
'login.auth.MYPROJECT': 'MY_USERNAME'
},
TokenDuration: 86400
};
var cognito = new AWS.CognitoIdentity({
region: AWS.config.region
});
cognito.getOpenIdTokenForDeveloperIdentity(params, function(err, data) {
if (err) {
return callback(err);
}
else {
/*AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: params.IdentityPoolId
});*/
AWS.config.credentials.get(function(){
// Credentials will be available when this function is called.
var accessKeyId = AWS.config.credentials.accessKeyId;
var secretAccessKey = AWS.config.credentials.secretAccessKey;
var sessionToken = AWS.config.credentials.sessionToken;
callback(null, {
identityId: data.IdentityId,
token: data.Token,
accessKeyId: accessKeyId,
secretAccessKey: secretAccessKey,
sessionToken: sessionToken
});
});
}
});
}
Both token and sessionToken return Unauthorized. Can someone tell me what is missing here?
Much appreciated.
EDIT 2016-11-15
The 'register' lambda code:
const AWS = require('aws-sdk');
exports.handler = (event, context, callback) => {
AWS.config.region = 'us-east-1'; // Region
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'MY_IDENTITY_POOL_ID',
});
var poolData = {
UserPoolId : 'MY_USER_POOL_ID',
ClientId : 'MY_CLIENT_ID'
};
var userPool = new AWS.CognitoIdentityServiceProvider(poolData);
var email = "myemail+" + Math.floor(Math.random() * (100 - 1) + 1) + "#example.com";
var params = {
ClientId: 'MY_CLIENT_ID',
Password: '1234567890',
Username: 'testaccount' + Math.floor(Math.random() * (100 - 1) + 1),
UserAttributes: [
{
Name: 'email',
Value: email
}
]
};
userPool.signUp(params, function(err, result){
if (err) {
console.log(err)
return;
}
callback(null, {
"message": "Hello from Lambda",
"data": result
});
});
};
My 'activate' lambda code is the following:
const AWS = require('aws-sdk');
exports.handler = (event, context, callback) => {
AWS.config.region = 'us-east-1'; // Region
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'MY_IDENTITY_POOL_ID',
});
var poolData = {
UserPoolId : 'MY_USER_POOL_ID',
ClientId : 'MY_CLIENT_ID'
};
var userPool = new AWS.CognitoIdentityServiceProvider(poolData);
var email = "email_address#example.com";
var params = {
ClientId: 'MY_CLIENT_ID',
Username: 'test_username',
ForceAliasCreation: false,
ConfirmationCode: '927000'
};
userPool.confirmSignUp(params, function(err, result){
if (err) {
console.log(err)
return;
}
callback(null, {
"message": "Hello from Lambda",
"data": result
});
});
};
In APIG, I created a Cognito User Pool Authorizer, selected my user pool, gave it a name, and set the identity token source to 'method.request.header.Authorization'.
In my APIG resource under the Method Request, I've set Authorization to my Cognito User Pool Authorizer. Additionally, API Key Required is set to true and I've a couple of keys I was testing with and that caused no issues.
I hope this covers everything.