Im currently using a USER-POOLS authorizer to get the first 3 tokens for my API:
idToken
refreshToken
accessToken
From here I would like to request credentials to be able to SigV4 request to my already set up API gateway, but first I need to get the requested credentials in order to do the SigV4.
In the docs I found this:
// Set the region where your identity pool exists (us-east-1, eu-west-1)
AWSCognito.config.region = 'us-east-1';
// Configure the credentials provider to use your identity pool
AWSCognito.config.credentials = new AWSCognito.CognitoIdentityCredentials({
IdentityPoolId: 'us-east-1:009xxxx ...',
});
// Make the call to obtain credentials
AWSCognito.config.credentials.get(function(){
// Credentials will be available when this function is called.
var accessKeyId = AWSCognito.config.credentials.accessKeyId;
var secretAccessKey = AWSCognito.config.credentials.secretAccessKey;
var sessionToken = AWSCognito.config.credentials.sessionToken;
});
To my surprise, the callback is called but the values for the
- accessKeyId
- secretAccessKey
- sessionToken
are all null.
I was expecting some kind of method, where I send my first idToken, and based on that I get the credentials, but it looks like this is all figured out under the hood?, anyways it is not working for me.
After some research, I realised that there is an undocumented way of doing this.
You need to construct this object first:
let url = 'cognito-idp.' + 'identity pool region' + '.amazonaws.com/' + 'your user pool id';
let logins = {};
logins[url] = idTokenJwt; // <- the one obtained before
let params = {
IdentityPoolId: 'the federated identity pool id',
Logins: logins
};
let creds = new AWS.CognitoIdentityCredentials(params);
AWS.config.region = 'us-east-1';
AWS.config.credentials = creds;
creds.get(function (err: any) {
if (!err) {
console.log("returned without error"); // <-- this gets called!!!
// and the values are correctly set!
var accessKeyId = AWS.config.credentials.accessKeyId;
var secretAccessKey = AWS.config.credentials.secretAccessKey;
var sessionToken = AWS.config.credentials.sessionToken;
}
else{
console.log("returned with error"); // <-- might get called if something is missing, anyways self-descriptive.
console.log(err);
}
});
In my case I still had to configure the trust relationship between the role and the identity pool, here the example:
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Federated": "cognito-identity.amazonaws.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"cognito-identity.amazonaws.com:aud": "your federated identity pool id"
},
"ForAnyValue:StringLike": {
"cognito-identity.amazonaws.com:amr": "authenticated"
}
}
}
*You can also replace "authenticated" with "unauthenticated", "graph.facebook.com", "google ...", depending your needs.
Related
i use a custom open id provider and aws accept my tokens and i'm able to use coginto identity pools to limit the access to my dynamodb database. My problem is that when i use coginito identity with dynamodb:LeadingKeys -> ${cognito-identity.amazonaws.com:sub}' it always prepend the aws-region before my userId: Example: eu-central-1:1234567
In my database design i only need the userId (without the region) as the primary. Are there any possibilities to remove the region from sub. i already tried to change the Condition to my custom openid provider (like the documentation described) - but this always don't work
my Policy:
- Effect: Allow
Action:
- dynamodb:DescribeTable
- dynamodb:Query
- dynamodb:GetItem
- dynamodb:PutItem
- dynamodb:UpdateItem
- dynamodb:DeleteItem
- dynamodb:BatchWriteItem
Resource:
- arn:aws:dynamodb:eu-central-1:123:table/table
Condition:
ForAllValues:StringEquals:
dynamodb:LeadingKeys: ${custom.open.id/openid:sub}
My Javascript code looks like this:
const Logins = {}
Logins['custom.open.id'] = accessToken; // my own openId access JWT Token
// Add the User's Id Token to the Cognito credentials login map.
const credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: identityPoolId,
Logins: Logins
});
return credentials.getPromise()
.then( error => {
if (error) {
return Promise.reject(error)
}
if (credentials.needsRefresh() === true) {
return credentials.refreshPromise()
}
return null;
})
.then(error => {
if (error) {
return Promise.reject(error)
}
console.log('Successfully logged!', credentials.data);
const dynamoDb = new AWS.DynamoDB.DocumentClient({
credentials: credentials,
region: region,
});
const params = {
TableName: "table",
KeyConditionExpression: "#userId = :userId",
ExpressionAttributeNames: {
"#userId": "userId"
},
ExpressionAttributeValues: {
":userId": currentUserId
}
}
return dynamoDb.query(params).promise();
})
.then(data => {
console.log("DynamoDb", data)
})
And the content of my JWT Access token is:
{
"sub": "123",
"nonce": "VRN3voQIhS6Nb6AzSsv907GxPnKc0szo",
"sid": "4fd7fd36-5a36-40e6-b381-b004a52be473",
"at_hash": "wF9BX32r6yQqvV5j0QGj8g",
"s_hash": "NzqHNkNF7FfCJa1tKudjTg",
"aud": "test_client",
"exp": 1556560701,
"iat": 1556557101,
"iss": "https://custom.open.id/openid"
}
The Sub in this IAM JSON is the Identity ID. An Identity ID is defined as a unique Identity for each user attempting to get credentials via a Cognito Identity Pool.
There is no way to change the pattern of an Identity ID, as the format is predefined by Cognito's architecture. For more details on Cognito Identity Pool's Roles and Policies, kindly refer to this official AWS Blog Post.
I want to embed Quicksight dashboard to an application. I have gone through the AWS quicksight documents, I did not get where I will find secure signed dashboard url.
In order to generate Quicksight secure dashboard url, follow the below steps:
Step 1: Create a new Identity Pool. Go to https://console.aws.amazon.com/cognito/home?region=us-east-1 , click ‘Create new Identity Pool’
Give an appropriate name.
Go to the Authentication Providers section, select Cognito.
Give the User Pool ID(your User pool ID) and App Client ID (go to App Clients in userpool and copy id).
Click ‘Create Pool’. Then click ‘Allow’ to create roles of the identity pool in IAM.
Step 2: Assign Custom policy to the Identity Pool Role
Create a custom policy with the below JSON.
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "quicksight:RegisterUser",
"Resource": "*",
"Effect": "Allow"
},
{
"Action": "quicksight:GetDashboardEmbedUrl",
"Resource": "*",
"Effect": "Allow"
},
{
"Action": "sts:AssumeRole",
"Resource": "*",
"Effect": "Allow"
}
]
}
Note: if you want to restrict the user to only one dashboard, replace the * with the dashboard ARN name in quicksight:GetDashboardEmbedUrl,
then goto the roles in IAM.
select the IAM role of the Identity pool and assign custom policy to the role.
Step 3: Configuration for generating the temporary IAM(STS) user
Login to your application with the user credentials.
For creating temporary IAM user, we use Cognito credentials.
When user logs in, Cognito generates 3 token IDs - IDToken, AccessToken, RefreshToken. These tokens will be sent to your application server.
For creating a temporary IAM user, we use Cognito Access Token and credentials will look like below.
AWS.config.region = 'us-east-1';
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId:"Identity pool ID",
Logins: {
'cognito-idp.us-east-1.amazonaws.com/UserPoolID': AccessToken
}
});
For generating temporary IAM credentials, we call sts.assume role method with the below parameters.
var params = {
RoleArn: "Cognito Identity role arn",
RoleSessionName: "Session name"
};
sts.assumeRole(params, function (err, data) {
if (err) console.log( err, err.stack); // an error occurred
else {
console.log(data);
})
You can add additional parameters like duration (in seconds) for the user.
Now, we will get the AccessKeyId, SecretAccessKey and Session Token of the temporary user.
Step 4: Register the User in Quicksight
With the help of same Cognito credentials used in the Step 3, we will register the user in quicksight by using the quicksight.registerUser method with the below parameters
var params = {
AwsAccountId: “account id”,
Email: 'email',
IdentityType: 'IAM' ,
Namespace: 'default',
UserRole: ADMIN | AUTHOR | READER | RESTRICTED_AUTHOR | RESTRICTED_READER,
IamArn: 'Cognito Identity role arn',
SessionName: 'session name given in the assume role creation',
};
quicksight.registerUser(params, function (err, data1) {
if (err) console.log("err register user”); // an error occurred
else {
// console.log("Register User1”);
}
})
Now the user will be registered in quicksight.
Step5: Update AWS configuration with New credentials.
Below code shows how to configure the AWS.config() with new credentials generated Step 3.
AWS.config.update({
accessKeyId: AccessToken,
secretAccessKey: SecretAccessKey ,
sessionToken: SessionToken,
"region": Region
});
Step6: Generate the EmbedURL for Dashboards:
By using the credentials generated in Step 3, we will call the quicksight.getDashboardEmbedUrl with the below parameters
var params = {
AwsAccountId: "account ID",
DashboardId: "dashboard Id",
IdentityType: "IAM",
ResetDisabled: true,
SessionLifetimeInMinutes: between 15 to 600 minutes,
UndoRedoDisabled: True | False
}
quicksight.getDashboardEmbedUrl(params,
function (err, data) {
if (!err) {
console.log(data);
} else {
console.log(err);
}
});
Now, we will get the embed url for the dashboard.
Call the QuickSightEmbedding.embedDashboard from front end with the help of the above generated url.
The result will be the dashboard embedded in your application with filter controls.
this link will give you what you need from aws cli https://aws.amazon.com/blogs/big-data/embed-interactive-dashboards-in-your-application-with-amazon-quicksight/
this is the step 3 aws cli cmd to give you embeded URL ( i was able to excecute)
aws quicksight get-dashboard-embed-url --aws-account-id (your account ID) --dashboard-id (your dashgboard ID) --identity-type IAM
there are many other dependence to enable the embeded dashboard per aws dcouments. i have not able to successfully doen that. GL and let me know if you make it happen!
PHP implementation
(in addition to Siva Sumanth's answer)
https://gist.github.com/evgalak/d0d1adf099e2d7bff741c16a89bf30ba
Our firm has built a custom admin portal and we want to provide our users a new link called reports which will link to aws quicksight dashboard but we don't want them to log in again in quicksight we cant the app (admin portal) to auto log them in with a specific role to see the dashboard. How can we achieve this?
Note: This answer is applicable only if you are using AWS Cognito
In order to generate Quicksight secure dashboard url, follow the below steps:
Step 1: Create a new Identity Pool. Go to https://console.aws.amazon.com/cognito/home?region=us-east-1 , click ‘Create new Identity Pool’
Give an appropriate name.
Go to the Authentication Providers section, select Cognito.
Give the User Pool ID(your User pool ID) and App Client ID (go to App Clients in userpool and copy id).
Click ‘Create Pool’. Then click ‘Allow’ to create roles of the identity pool in IAM.
Step 2: Assign Custom policy to the Identity Pool Role
Create a custom policy with the below JSON.
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "quicksight:RegisterUser",
"Resource": "*",
"Effect": "Allow"
},
{
"Action": "quicksight:GetDashboardEmbedUrl",
"Resource": "*",
"Effect": "Allow"
},
{
"Action": "sts:AssumeRole",
"Resource": "*",
"Effect": "Allow"
}
]
}
Note: if you want to restrict the user to only one dashboard, replace the * with the dashboard ARN name in quicksight:GetDashboardEmbedUrl,
then goto the roles in IAM.
select the IAM role of the Identity pool and assign custom policy to the role.
Step 3: Configuration for generating the temporary IAM(STS) user
Login to your application with the user credentials.
For creating temporary IAM user, we use Cognito credentials.
When user logs in, Cognito generates 3 token IDs - IDToken, AccessToken, RefreshToken. These tokens will be sent to your application server.
For creating a temporary IAM user, we use Cognito Access Token and credentials will look like below.
AWS.config.region = 'us-east-1';
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId:"Identity pool ID",
Logins: {
'cognito-idp.us-east-1.amazonaws.com/UserPoolID': AccessToken
}
});
For generating temporary IAM credentials, we call sts.assume role method with the below parameters.
var params = {
RoleArn: "Cognito Identity role arn",
RoleSessionName: "Session name"
};
sts.assumeRole(params, function (err, data) {
if (err) console.log( err, err.stack); // an error occurred
else {
console.log(data);
})
You can add additional parameters like duration (in seconds) for the user.
Now, we will get the AccessKeyId, SecretAccessKey and Session Token of the temporary user.
Step 4: Register the User in Quicksight
With the help of same Cognito credentials used in the Step 3, we will register the user in quicksight by using the quicksight.registerUser method with the below parameters
var params = {
AwsAccountId: “account id”,
Email: 'email',
IdentityType: 'IAM' ,
Namespace: 'default',
UserRole: ADMIN | AUTHOR | READER | RESTRICTED_AUTHOR | RESTRICTED_READER,
IamArn: 'Cognito Identity role arn',
SessionName: 'session name given in the assume role creation',
};
quicksight.registerUser(params, function (err, data1) {
if (err) console.log("err register user”); // an error occurred
else {
// console.log("Register User1”);
}
})
Now the user will be registered in quicksight.
Step5: Update AWS configuration with New credentials.
Below code shows how to configure the AWS.config() with new credentials generated Step 3.
AWS.config.update({
accessKeyId: AccessToken,
secretAccessKey: SecretAccessKey ,
sessionToken: SessionToken,
"region": Region
});
Step6: Generate the EmbedURL for Dashboards:
By using the credentials generated in Step 3, we will call the quicksight.getDashboardEmbedUrl with the below parameters
var params = {
AwsAccountId: "account ID",
DashboardId: "dashboard Id",
IdentityType: "IAM",
ResetDisabled: true,
SessionLifetimeInMinutes: between 15 to 600 minutes,
UndoRedoDisabled: True | False
}
quicksight.getDashboardEmbedUrl(params,
function (err, data) {
if (!err) {
console.log( data);
} else {
console.log(err);
}
}
);
Now, we will get the embed url for the dashboard.
Call the QuickSightEmbedding.embedDashboard from front end with the help of the above generated url.
The result will be the dashboard embedded in your application with filter controls.
AWS support single sign on.
I believe you can use that feature for the users.
please click here for more information
I want to call an AWS API Gateway Endpoint that is protected with AWS_IAM using the generated JavaScript API SDK.
I have a Cognito UserPool and a Cognito Identity Pool. Both properly synced via ClientId.
I use this code to Sign in and get the Cognito Identity
AWS.config.region = 'us-east-1'; // Region
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'us-east-1:XXXXXXXXXXXXXXXXXXXXXXXX' // your identity pool id here
});
AWSCognito.config.region = 'us-east-1';
AWSCognito.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'us-east-1:XXXXXXXXXXXXXXXXXXXXXXXX' // your identity pool id here
});
var poolData = {
UserPoolId: 'us-east-1_XXXXXXXX',
ClientId: 'XXXXXXXXXXXXXXXXXXXXXXXX'
};
var userPool = new AWSCognito.CognitoIdentityServiceProvider.CognitoUserPool(poolData);
var authenticationData = {
Username: 'user',
Password: '12345678',
};
var authenticationDetails = new AWSCognito.CognitoIdentityServiceProvider.AuthenticationDetails(authenticationData);
var userData = {
Username: 'user',
Pool: userPool
};
var cognitoUser = new AWSCognito.CognitoIdentityServiceProvider.CognitoUser(userData);
cognitoUser.authenticateUser(authenticationDetails, {
onSuccess: function (result) {
console.log('access token + ' + result.getAccessToken().getJwtToken());
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'us-east-1:XXXXXXXXXXXXXXXXXXXX',
IdentityId: AWS.config.credentials.identityId,
Logins: {
'cognito-idp.us-east-1.amazonaws.com/us-east-1_XXXXXX': result.idToken.jwtToken
}
});
AWS.config.credentials.get(function (err) {
// now I'm using authenticated credentials
if(err)
{
console.log('error in autheticatig AWS'+err);
}
else
{
console.log(AWS.config.credentials.identityId);
}
});
},
onFailure: function (err) {
alert(err);
}
});
All this succeeds and I have an authorized Cognito Identity now.
Now I try to call the API Gateway Endpoint to execute the Lambda Function it points to.
var apigClient = apigClientFactory.newClient({
accessKey: AWS.config.credentials.accessKeyId, //'ACCESS_KEY',
secretKey: AWS.config.credentials.secretAccessKey, //'SECRET_KEY',
sessionToken: AWS.config.credentials.sessionToken, // 'SESSION_TOKEN', //OPTIONAL: If you are using temporary credentials you must include the session token
region: 'us-east-1' // OPTIONAL: The region where the API is deployed, by default this parameter is set to us-east-1
});
var params = {
// This is where any modeled request parameters should be added.
// The key is the parameter name, as it is defined in the API in API Gateway.
};
var body = {
// This is where you define the body of the request,
query: '{person {firstName lastName}}'
};
var additionalParams = {
// If there are any unmodeled query parameters or headers that must be
// sent with the request, add them here.
headers: {},
queryParams: {}
};
apigClient.graphqlPost(params, body, additionalParams)
.then(function (result) {
// Add success callback code here.
console.log(result);
}).catch(function (result) {
// Add error callback code here.
console.log(result);
});
But unfortunately this fails. The OPTIONS request succeeds with 200 but the POST then fails with 403.
I am pretty sure that there is no CORS problem here.
I am pretty sure the problem has to do with IAM Roles and AWS Resource Configurations.
My question is basically, can you please provide me with all the necessary AWS Resource Configurations and IAM Roles that are necessary for this to work please?
Resources I have are
API Gateway - with deployed API Endpoints
Lambda Function - called by the Endpoint
Cognito User Pool - with App synced to the Identity Pool
Cognito Identity Pool - with Authorized and Unauthorized Role mapped to it.
IAM Roles - for the Lambda Function and the Authorized and Unauthorized Role of the Cognito Identity Pool.
But I don't know how these Resources need to be configured properly to get this to work.
Thank you
What access permissions does the role of the Cognito Identity have? Make sure it has access to perform execute-api:Invoke on your API.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"execute-api:Invoke"
],
"Resource": [
"arn:aws:execute-api:us-east-1:<account>:<rest-api>/*/POST/graphql"
]
}
]
}
You can get the exact resource ARN from the method settings page in the web console.
Even after following everything I was getting the same error. And the reason was I missed the "sessionToken" while initialising the apigClient.
var apigClient = apigClientFactory.newClient({
accessKey: AWS.config.credentials.accessKeyId, //'ACCESS_KEY',
secretKey: AWS.config.credentials.secretAccessKey, //'SECRET_KEY',
sessionToken: AWS.config.credentials.sessionToken, // 'SESSION_TOKEN', //OPTIONAL: If you are using temporary credentials you must include the session token
region: 'us-east-1' // OPTIONAL: The region where the API is deployed, by default this parameter is set to us-east-1 });
//OPTIONAL: If you are using temporary credentials you must include the session token -- is not really optional
I have selected "Allow access to one or more AWS accounts or IAM users"
My access policy
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::12345678910:user/elastic"
},
"Action": "es:*",
"Resource": "arn:aws:es:eu-west-1:123456789:domain/elastic-cluster/*"
}
]
}
I have created an IAM profile -
user - elastic
password -hisdfdsfds
Access key Id - sdsfdssdfdsfdsfdsfsdfsd
Secret Access Key - sdsfdsfdsfsdfdsfds
when I try to connect
$params = array();
$params['hosts'] = array (
'search-elastic-cluster-sdfsdfsdfs.eu-east.es.amazonaws.com:80',
);
$client = new Elasticsearch\Client($params);
It throws the following error:
{"Message":"User: anonymous is not authorized to perform: es:ESHttpPost on resource: arn:aws:es:eu-west-1:dsfdsfsdfsdsd:domain/elastic-cluster/sdsfsfds/sdfdsfdssd/_search"}
I found it can be accessed by signed version 4 signature requests. I tried doing it, but could not . Maybe the way is wrong.
I would be happy if some one suggests ideas in creating signed version 4 request to elasticsearch domain. An example using parameters I stated above would be very helpful. Thanks in advance.
The application needs to sign the requests going to Elasticsearch. The AWS SDK for your language of choice should have a method which creates the credentials for the sign request.
When you provide your requests with the credentials, it should be ok and good to go.
This is a code snippet using the javascript sdk:
var AWS = require('aws-sdk');
var creds = new AWS.EnvironmentCredentials('AWS');
var esDomain = {
region: 'us-east-1',
endpoint: 'yoursearchdomain.region.amazonaws.com',
index: 'myindex',
doctype: 'mytype'
};
var endpoint = new AWS.Endpoint(esDomain.endpoint);
var req = new AWS.HttpRequest(endpoint);
req.method = 'POST';
req.path = path.join('/', esDomain.index, esDomain.doctype);
req.region = esDomain.region;
req.headers['presigned-expires'] = false;
req.headers['Host'] = endpoint.host;
req.headers['Content-Type'] = 'application/json';
req.body = doc;
var signer = new AWS.Signers.V4(req , 'es');
signer.addAuthorization(creds, new Date());
var send = new AWS.NodeHttpClient();
send.handleRequest(req, null, function(httpResp) {
var respBody = '';
httpResp.on('data', function (chunk) {
respBody += chunk;
});
httpResp.on('end', function (chunk) {
console.log('Response: ' + respBody);
context.succeed('Lambda added document ' + doc);
});
}, function(err) {
console.log('Error: ' + err);
context.fail('Lambda failed with error ' + err);
});