AWS Amplify Storage.get() - AWSAccessKeyId is undefined - amazon-web-services

I'm struggling with a react native project utilizing AWS amplify, both Auth and Storage.
Calling Storage from this service file in my project:
import Amplify, {Auth, Storage} from 'aws-amplify'
import config from './config'
Amplify.configure({
Auth: config.Auth,
Storage: config.Storage,
})
export {
Auth,
Storage,
}
config is:
AWS: {
Auth: {
region: 'us-east-X',
userPoolId: 'us-east-XXXXXXX',
userPoolWebClientId: 'XXXXXXXXX',
identityPoolId: 'us-east-X:XXXXXXXXXXXXXX',
},
Storage: {
AWSS3: {
bucket: 'XXXXXXX',
region: 'us-east-X',
},
},
},
By this point, the user has authenticated with Auth. Calling:
Storage.get('public/fileName.gif', { expires: 120 })
Results in a signed URL that appears to be missing the access key, which it should be generating from the IAM logged in user.
Here's an example signed URL it generates:
https://expyhealth-stg.s3.amazonaws.com/public/activityImages/Ankle%20Pumps.gif?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=undefined%2F20201020%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20201020T204616Z&X-Amz-Expires=120&X-Amz-Signature=f40bad142a9b190f9d9959bb9db0ad077c0cecab5171098f033a700cb9aa45b5&X-Amz-SignedHeaders=host&x-amz-user-agent=aws-sdk-js-v3-react-native-%40aws-sdk%2Fclient-s3%2F1.0.0-gamma.8%20aws-amplify%2F3.6.0%20react-native&x-id=GetObject"
Notice the X-Amz-Credential=undefined
I've been following the thread here for hours and keep coming up short. I cannot determine why it isn't generating the access key.
Using aws-amplify version 3.3.4
Here is the bucket policy:
{
"Version": "2012-10-17",
"Id": "Policy1599854584652",
"Statement": [
{
"Sid": "Stmt1599854581275",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::XXXXXXXXXXXX:role/Cognito_ExpyHealthStagingAuth_Role"
},
"Action": "s3:GetObject",
"Resource": [
"arn:aws:s3:::XXXXXXXX",
"arn:aws:s3:::XXXXXXXX/*"
]
}
]
}

I solve a similar issue by editing the IAM trust relationship as follows:
Open the AWS console
Go to IAM
Go to roles
Select the role specified as the Authenticated role of your identity pool
Open "Trust Relationship" tab
Click "Edit trust relationship"
Paste the following:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "cognito-identity.amazonaws.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"cognito-identity.amazonaws.com:aud": "eu-west-1:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
},
"ForAnyValue:StringLike": {
"cognito-identity.amazonaws.com:amr": "authenticated"
}
}
}
]
}
Tip: compare your configuration with the one generated by the AWS Amplify CLI.

Related

Identity Pool Role Can't Access S3 Bucket Access Point

Summary: I am using AWS Amplify Auth class with a pre-configured Cognito User Pool for authentication. After authentication, I am using the Cognito ID token to fetch identity pool credentials (using AWS CredentialProviders SDK) whose assumed role is given access to an S3 access point. I then attempt to fetch a known object from the bucket's access point using the AWS S3 SDK. The problem is that the request returns a response of 403 Forbidden instead of successfully getting the object, despite my role policy and bucket (access point) policy allowing the s3:GetObject action on the resource.
I am assuming something is wrong with the way my policies are set up. Code snippets below.
I am also concerned I'm not getting the right role back from the credentials provider, but I don't allow unauthenticated roles on the identity pool so I am not sure, and I don't know how to verify the role being sent back in the credentials' session token to check.
I also may not be configuring the sdk client objects properly, but I followed the documentation provided to the best of my understanding from the documentation (I am using AWS SDK v3, not v2, so slightly different syntax and uses modular imports)
Backend Configurations - IAM
Identity Pool: Authenticated Role Trust Policy
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "cognito-identity.amazonaws.com"
},
"Action": [
"sts:AssumeRoleWithWebIdentity",
"sts:TagSession"
],
"Condition": {
"StringEquals": {
"cognito-identity.amazonaws.com:aud": "<MY_IDENTITY_POOL_ID>"
},
"ForAnyValue:StringLike": {
"cognito-identity.amazonaws.com:amr": "authenticated"
}
}
}
]
}
Identity Pool: Authenticated Role S3 Access Policy
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:GetObjectVersion"
],
"Resource": "arn:aws:s3:::<MY_ACCESS_POINT_NAME>/object/*"
}
]
}
Backend Configurations - S3
S3 Bucket and Access Points: Block All Public Access
S3 Bucket CORS Policy:
[
{
"AllowedHeaders": [
"*"
],
"AllowedMethods": [
"GET",
"PUT",
"HEAD"
],
"AllowedOrigins": [
"*"
],
"ExposeHeaders": [],
"MaxAgeSeconds": 300
}
]
S3 Bucket Policy (Delegates Access Control to Access Points):
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DelegateAccessControlToAccessPoints",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "*",
"Resource": [
"arn:aws:s3:::<MY_BUCKET_NAME>",
"arn:aws:s3:::<MY_BUCKET_NAME>/*"
],
"Condition": {
"StringEquals": {
"s3:DataAccessPointAccount": "<MY_ACCT_ID>"
}
}
}
]
}
Access Point Policy
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowAccessPointToGetObjects",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::<ACCT_ID>:role/<MY_IDENTITY_POOL_AUTH_ROLE_NAME>"
},
"Action": [
"s3:GetObject",
"s3:GetObjectVersion"
],
"Resource": "arn:aws:s3:<REGION>:<ACCT_ID>:accesspoint/<MY_ACCESS_POINT_NAME>/object/*"
}
]
}
Front End AuthN & AuthZ
Amplify Configuration of User Pool Auth
Amplify.configure({
Auth: {
region: '<REGION>',
userPoolId: '<MY_USER_POOL_ID>',
userPoolWebClientId: '<MY_USER_POOL_APP_CLIENT_ID>'
}
})
User AuthZ process:
On user login event, call Amplify's Auth.signIn() which returns type CognitoUser:
// Log in user (error checking ommitted here for post)
const CognitoUser = await Auth.signIn(email, secret);
// Get ID Token JWT
const CognitoIdToken = CognitoUser.signInUserSession.getIdToken().getJwtToken();
// Use #aws-sdk/credentials-provider to get Identity Pool Credentials
const credentials = fromCognitoIdentityPool({
clientConfig: { region: '<REGION>' },
identityPoolId: '<MY_IDENTITY_POOL_ID>',
logins: {
'cognito-idp.<REGION>.amazonaws.com/<MY_USER_POOL_ID>': CognitoIdToken
}
})
// Create S3 SDK Client
client = new S3Client({
region: '<REGION>',
credentials
})
// Format S3 GetObjectCommand parameters for object to get from access point
const s3params = {
Bucket: '<MY_ACCESS_POINT_ARN>',
Key: '<MY_OBJECT_KEY>'
}
// Create S3 client command object
const getObjectCommand = new GetObjectCommand(s3params);
// Get object from access point (execute command)
const response = await client.send(getObjectCommand); // -> 403 FORBIDDEN

AWS Redshift Serverless: `ERROR: Not authorized to get credentials of role`

I've created a serverless Redshift instance, and I'm trying to import a CSV file from an S3 bucket.
I've made an IAM role with full Redshift + Redshift serverless access and S3 Read access, and added this role as a Default Role under the Permissions settings of the Serverless Configuration. Basically, I've tried to do anything that I thought should be necessary according to the documentation.
However, there docs are only targeted at the normal EC2 hosted Redshift for now, and not for the Serverless edition, so there might be something that I've overlooked.
But when I try running a COPY command (generated by the UI), I get this error:
ERROR: Not authorized to get credentials of role arn:aws:iam::0000000000:role/RedshiftFull Detail: ----------------------------------------------- error: Not authorized to get credentials of role arn:aws:iam::00000000:role/RedshiftFull code: 30000 context: query: 18139 location: xen_aws_credentials_mgr.cpp:402 process: padbmaster [pid=8791] ----------------------------------------------- [ErrorId: 1-61dc479b-570a4e96449b228552f2c911]
Here's the command I'm trying to run:
COPY dev."test-schema"."transactions" FROM 's3://bucket-name/something-1_2021-11-01T00_00_00.000Z_2022-01-03.csv' IAM_ROLE 'arn:aws:iam::0000000:role/RedshiftFull' FORMAT AS CSV DELIMITER ',' QUOTE '"' REGION AS 'eu-central-1'
Here's the Role
{
"Role": {
"Path": "/",
"RoleName": "RedshiftFull",
"RoleId": "AROA2PAMxxxxxxx",
"Arn": "arn:aws:iam::000000000:role/RedshiftFull",
"CreateDate": "2022-01-10T13:55:03+00:00",
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"redshift.amazonaws.com",
"sagemaker.amazonaws.com"
]
},
"Action": "sts:AssumeRole"
}
]
},
"Description": "Allows Redshift clusters to call AWS services on your behalf.",
"MaxSessionDuration": 3600,
"RoleLastUsed": {}
}
}
{
"AttachedPolicies": [
{
"PolicyName": "redshift-serverless",
"PolicyArn": "arn:aws:iam::719432241830:policy/redshift-serverless"
},
{
"PolicyName": "AmazonRedshiftFullAccess",
"PolicyArn": "arn:aws:iam::aws:policy/AmazonRedshiftFullAccess"
},
{
"PolicyName": "AmazonS3ReadOnlyAccess",
"PolicyArn": "arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess"
}
]
}
The redshift-serverless policy is here:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "redshift-serverless:*",
"Resource": "*"
}
]
}

Cross account IAM roles for Kubernetes service account - s3 bucket

Hey im trying to cross account access for a role. i have 2 accounts: prod and non-prod.
and bucket in prod account, which im trying to write files to there from a non-prod role which is used as a service account in k8s cluster.
in prod account i configured:
a role with the following policy(read write access to the bucket):
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ListObjectsInBucket",
"Effect": "Allow",
"Action": [
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::test2"
]
},
{
"Sid": "AllObjectActions",
"Effect": "Allow",
"Action": "s3:*Object",
"Resource": [
"arn:aws:s3:::test2/*"
]
}
]
}
and the following trust:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::non-prod-AccountID:role/name-of-the-non-prod-role"
},
"Action": "sts:AssumeRole",
"Condition": {}
}
]
}
in non prod i configured:
a role with the following policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::prod-Account-ID:role/prod-role-name"
},
"Action": "sts:AssumeRole",
"Condition": {}
}
]
}
and trust as follows:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::non-prod-accountID:oidc-provider/oidc.eks.us-east-1.amazonaws.com/id/1111111111111111111"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"oidc.eks.us-east-1.amazonaws.com/id/1111111111111111111:sub":
"system:serviceaccount:name-space:name-of-the-service-account"
}
}
}
]
}
serviceAccount annotation is:
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::non-prod-AccountID:role/non-prod-role-name
when running the command from inside the pod with the service account of the role in non-prod:
aws s3 cp hello.txt s3://test2/hello.txt
im having:
upload failed: ./hello.txt to s3://test2/hello.txt An error occurred (AccessDenied) when calling the PutObject operation: Access Denied
by the way the cluster is in another account (devops account) if its related, surely added OIDC provider identity to both non-prod and prod accounts as identity provider.
If you're getting the error An error occurred (InvalidIdentityToken) when calling the AssumeRoleWithWebIdentity operation: No OpenIDConnect provider found in your account for $oidc_url when trying to cross-account assume roles, but you can assume roles in your cluster account normally, here's some points:
EKS ACCOUNT
Create a ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
name: $sa_name
namespace: $eks_ns
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::$resource_account_id:role/$role_name
Annotate your deployment
spec.template.spec:
serviceAccountName: $sa_name
Get info about your cluster OIDC Provider
aws iam get-open-id-connect-provider --open-id-connect-provider-arn arn:aws:iam::$eks_cluster_account_id:oidc-provider/$oidc_provider
3.1. The output will be like:
{
"Url": "...",
"ClientIDList": ["..."],
"ThumbprintList": ["..."],
"CreateDate": "...",
"Tags": [...]
}
3.2. Take note of the outputs (Url and ThumbprintList specially)
RESOURCE ACCOUNT
Add the provider (if you don`t have it already), using the output from your cluster account
aws iam create-open-id-connect-provider --url $oidc_url --client-id-list sts.amazonaws.com --thumbprint-list $oidc_thumbprint
This should be enought to the mentioned error stop. If you now get An error occurred (AccessDenied) when calling the AssumeRoleWithWebIdentity operation: Not authorized to perform sts:AssumeRoleWithWebIdentity, you're problably using the $eks_cluster_account_id on Principal.Federated, instead of $resource_account_id created on the previous step. So, make sure you're using the ARN from the IP that is assigned to the resource account, not the cluster account.
Create a role and a policy to access your resources with following trusted entities policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::$resource_account_id:oidc-provider/$oidc_provider"
},
"Action": "sts:AssumeRoleWithWebIdentity"
}
]
}
Also, there's no need to have two roles. One is enough.

How to configure AWS API Gateway to access it from another AWS account

I want to give access to IAM users from other accounts to be able to invoke my API.
I have these configurations in my API Gateway resource methods:
Authorization type: AWS_IAM (I tried with Auth type None as well..)
And Resource Policy defined as:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::<ACCOUNT_2>:user/ApiUser"
},
"Action": "execute-api:Invoke",
"Resource": "arn:aws:execute-api:us-west-2:<ACCOUNT_1>:<API_ID>/*/*/*"
}
]
}
I have also given invoke permissions to the IAM user of the other account:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"execute-api:Invoke"
],
"Resource": "arn:aws:execute-api:us-west-2:<ACCOUNT_1>:<API_ID>:test/GET/*"
}
]
}
I have deployed the API to a stage named test.
Still, I see the below error when I invoke the API with the credentials from the other account's user:
{
"message": "User: arn:aws:iam::<ACCOUNT_2>:user/ApiUser is not authorized to perform: execute-api:Invoke on resource: arn:aws:execute-api:us-west-<ACCOUNT_1>:<API_ID>/test/GET/foo/bar"
}
What am I missing here?
I followed this guide:
https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-resource-policies-examples.html
This has bitten me before, and may be your issue too.
After you SAVE your resource policy, you must ALSO deploy your API.
In the menu on the left, click up one level
Then under ACTIONS, select DEPLOY API

AWS ElasticSearch write to account "A" from lambda in account "B"

I have an AWS ElasticSearch Cluster in account "A".
I'm trying to create a lambda (triggered from a DynamoDB Stream) in account "B" that will write to ES in account "A".
I'm getting the following error:
{
"Message":"User: arn:aws:sts::AccountB:assumed-role/lambdaRole1/sourceTableToES is not authorized to perform: es:ESHttpPost on resource: beta-na-lifeguard"
}
I have tried putting the STS as well as the ROLE into the ES access policy (within account "A") with no luck. Here is my policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::AccountA:user/beta-elasticsearch-admin"
},
"Action": "es:*",
"Resource": "*"
},
{
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::AccountA:user/beta-elasticsearch-readwrite",
"arn:aws:iam::AccountA:role/beta-na-DynamoDBStreamLambdaElasticSearch",
"arn:aws:sts::AccountB:assumed-role/lambdaRole1/sourceTableToES",
"arn:aws:iam::AccountB:role/service-role/lambdaRole1"
]
},
"Action": [
"es:ESHttpGet",
"es:ESHttpPost",
"es:ESHttpPut"
],
"Resource": "*"
}
]
}
In my code above I was adding arn:aws:sts::AccountB:assumed-role/lambdaRole1/sourceTableToSNS into the AccountA ES access list, that is wrong. Instead do the following:
I already had arn:aws:iam::AccountA:role/beta-na-DynamoDBStreamLambdaElasticSearch in the ES access list, I needed to add a trust relationship (from the IAM role screen) for that role to be assumable by AccountB. I added this into the trust relationship:
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::AccountB:root"
},
"Action": "sts:AssumeRole"
}
Then, in my accountB lambda code, I needed to assume that role. Here is the relevent code from the lambda.
var AWS = require('aws-sdk');
var sts = new AWS.STS({ region: process.env.REGION });
var params = {
RoleSessionName: "hello-cross-account-session",
RoleArn: "arn:aws:iam::accountA:role/beta-na-DynamoDBStreamLambdaElasticSearch",
DurationSeconds: 900
};
sts.assumeRole(params, function (err, data) {
if (err) {
console.log(err, err.stack); // an error occurred
context.fail('failed to assume role ' + err);
return;
}
log("assumed role successfully! %j", data)
postToES(bulkUpdateCommand, context);
});
When you create a "role" for another account you also need to setup the "Trust relationships". This is done in the AWS IAM console under "Roles". Second tab for your role is "Trust relationships". You will need to specify the account details for the other account as trusted.
The "Trust relationships" is a policy document itself. Here is an example that will allow you to call AssumeRole from another account to my AWS account.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::2812XXXXYYYY:root"
},
"Action": "sts:AssumeRole"
}
]
}
In your role, just specify permissions as normal just like you were granting permissions for another IAM user / service (e.g. remove all those account type entries). The Trust relationships policy document defines who can call AssumeRole to be granted those permissions.
Creating a Role to Delegate Permissions to an IAM User
Modifying a Role