Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cognito unauthenticated user not authorized to perform: ssm:GetParameter because no session policy allows #4303

Closed
hienbx-0488 opened this issue Dec 20, 2022 · 4 comments
Assignees
Labels
bug This issue is a bug. needs-review This issue/pr needs review from an internal developer. p2 This is a standard priority issue

Comments

@hienbx-0488
Copy link

hienbx-0488 commented Dec 20, 2022

Describe the bug

I use cognito identity pool with enable access to unauthenticated identities .
For Unauthenticated role, i created new role with policy AmazonS3FullAccess and inline policy for get SSM Parameter store

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "ssm:*"
            ],
            "Resource": "*"
        }
    ]
}

I use blow code to get list bucket S3 and SSM Paramter Store

var AWS = require('aws-sdk');

var IDENTITY_POOL_ID = 'my_identity_pool_id';
var REGION = 'ap-northeast-1';

// Initialize the Amazon Cognito credentials provider
AWS.config.region = REGION; // Region
AWS.config.credentials = new AWS.CognitoIdentityCredentials({IdentityPoolId: IDENTITY_POOL_ID,});


// Create S3 service object
s3 = new AWS.S3({apiVersion: '2006-03-01'});

// Call S3 to list the buckets
s3.listBuckets(function(err, data) {
  if (err) {
    console.log("Error", err);
  } else {
    console.log("Success", data.Buckets);
  }
});


var ssm = new AWS.SSM({});
var params = {
  Name: 'abc', /* required */
  WithDecryption: false
};
ssm.getParameter(params, function(err, data) {
  if (err) console.log(err, err.stack); // an error occurred
  else     console.log(data);           // successful response
});

After run code, list bucket S3 return success, but SSM parameter store return error

{
  code: 'AccessDeniedException',
  time: 2022-12-20T08:05:41.500Z,
  requestId: 'bd8d4f26-7fd3-4bd3-ae40-dfaab59e62fb',
  statusCode: 400,
  retryable: false,
  retryDelay: 78.72879079767343
} AccessDeniedException: User: arn:aws:sts::****:assumed-role/bc-CognitoAnonymousGroupRol-***/CognitoIdentityCredentials is not authorized to perform: ssm:GetParameter on resource: arn:aws:ssm:ap-northeast-1:****:parameter/abc because no session policy allows the ssm:GetParameter action

Expected Behavior

Return success SSM parameter store

Current Behavior

Error when get SSM parameter store

Reproduction Steps

var AWS = require('aws-sdk');

var IDENTITY_POOL_ID = 'my_identity_pool_id';
var REGION = 'ap-northeast-1';

// Initialize the Amazon Cognito credentials provider
AWS.config.region = REGION; // Region
AWS.config.credentials = new AWS.CognitoIdentityCredentials({IdentityPoolId: IDENTITY_POOL_ID,});


// Create S3 service object
s3 = new AWS.S3({apiVersion: '2006-03-01'});

// Call S3 to list the buckets
s3.listBuckets(function(err, data) {
  if (err) {
    console.log("Error", err);
  } else {
    console.log("Success", data.Buckets);
  }
});


var ssm = new AWS.SSM({});
var params = {
  Name: 'abc', /* required */
  WithDecryption: false
};
ssm.getParameter(params, function(err, data) {
  if (err) console.log(err, err.stack); // an error occurred
  else     console.log(data);           // successful response
});

Possible Solution

No response

Additional Information/Context

No response

SDK version used

aws-sdk@2.244.1

Environment details (OS name and version, etc.)

Ubuntu 22.04, Javascript, aws-sdk@2.244.1

@hienbx-0488 hienbx-0488 added bug This issue is a bug. needs-triage This issue or PR still needs to be triaged. labels Dec 20, 2022
@david04
Copy link

david04 commented Mar 15, 2023

I seem to be having the same issue

@RanVaknin RanVaknin added the p2 This is a standard priority issue label Mar 29, 2023
@RanVaknin
Copy link
Contributor

Hi,

I apologize for the long wait time, but I was finally able to get some clarity on this one.

To get unauthenticated credentials, The Cognito identity service probably calls STS "under the hood" as a form of abstraction, but there is no way to provide a session policy. And while an AssumeRole with STS directly can take a Policy as an argument, CognitoIdentityCredentials (or the underlying API calls to Cognito) do not define Policy as an request parameter so it never gets passed on to STS.

I believe this is the use case:

export function fromCognitoIdentity(parameters: FromCognitoIdentityParameters): CognitoIdentityCredentialProvider {
  return async (): Promise<CognitoIdentityCredentials> => {
    const {
      Credentials: {
        AccessKeyId = throwOnMissingAccessKeyId(),
        Expiration,
        SecretKey = throwOnMissingSecretKey(),
        SessionToken,
      } = throwOnMissingCredentials(),
    } = await parameters.client.send(
      new GetCredentialsForIdentityCommand({
        CustomRoleArn: parameters.customRoleArn,
        IdentityId: parameters.identityId,
        Logins: parameters.logins ? await resolveLogins(parameters.logins) : undefined,
       // ideally there should have been a SessionPolicy: JSON.Stringify(jsonPolicyDocument) but the GetCredentialsForIdentityCommand doesn't offer this (service side limitation)
      })
    );

    return {
      identityId: parameters.identityId,
      accessKeyId: AccessKeyId,
      secretAccessKey: SecretKey,
      sessionToken: SessionToken,
      expiration: Expiration,
    };
  };
}

This triggers then a service side behavior that would automatically apply the Default Session Policy in case one is not provided explicitly. This can be observed by reviewing a CloudTrail log of an AssumeRoleWithWebIdentity to confirm the session policy.

Session Policies act similarly to Permissions Boundaries in that only the intersect of those policies and the identity-based permissions (inline or managed policy) can be allowed. Session policies are optional parameters, but if they are passed, they must allow the call. If they are not explicitly passed, then an implicit allow any-all session policy is leveraged.

The default session policy looks like this:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "cloudwatch:*",
                "logs:*",
                "dynamodb:*",
                "kinesis:*",
                "mobileanalytics:*",
                "s3:*",
                "ses:*",
                "sns:*",
                "sqs:*",
                "lambda:*",
                "machinelearning:*",
                "execute-api:*",
                "iot:*",
                "gamelift:*",
                "scs:*",
                "cognito-identity:*",
                "cognito-idp:*",
                "lex:*",
                "polly:*",
                "comprehend:*",
                "translate:*",
                "transcribe:*",
                "rekognition:*",
                "mobiletargeting:*",
                "firehose:*",
                "appsync:*",
                "personalize:*",
                "kms:Encrypt",
                "kms:Decrypt",
                "kms:ReEncrypt*",
                "kms:GenerateDataKey*",
                "sagemaker:InvokeEndpoint",
                "cognito-sync:*",
                "sumerian:View*",
                "codewhisperer:*",
                "textract:DetectDocumentText",
                "textract:AnalyzeDocument",
                "sdb:*"
            ],
            "Resource": [
                "*"
            ]
        }
    ]
}

Notice how "ssm:getParameter" is missing causing the role policy's explicit allow to not be evaluated.


The next step would be to check the implementation of this method in other SDKs to see if this is a JS SDK specific issue or a limitation with how Cognito Identity federates credentials.

Reproduction sample:

var AWS = require('aws-sdk');

var IDENTITY_POOL_ID = 'us-east-1:REDACTED';
var REGION = 'us-east-1';

// Initialize the Amazon Cognito credentials provider
AWS.config.region = REGION; // Region
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
    IdentityPoolId: IDENTITY_POOL_ID,
});



// ssm call with credentials obtained through cognito
var ssm = new AWS.SSM({});
var params = {
  Name: 'param-name', 
  WithDecryption: false
};
ssm.getParameter(params, function(err, data) {
  if (err) console.log(err, err.stack);
  else     console.log(data);         
});

Result:

{
   "message":"User: arn:aws:sts::REDACTED:assumed-role/REDACTED/CognitoIdentityCredentials is not authorized to perform: ssm:GetParameter on resource: arn:aws:ssm:us-east-1:REDACTED:parameter/param-name because no session policy allows the ssm:GetParameter action",
   "code":"AccessDeniedException",
   "time":"2023-06-01T23:21:00.711Z",
   "requestId":"REDACTED",
   "statusCode":400,
   "retryable":false,
   "retryDelay":17.636880855857928
}

The SDK team will need to investigate this further with the Cognito team.

Thanks,
Ran~

@RanVaknin RanVaknin self-assigned this Jun 1, 2023
@RanVaknin RanVaknin added needs-review This issue/pr needs review from an internal developer. and removed needs-triage This issue or PR still needs to be triaged. labels Jun 1, 2023
@RanVaknin
Copy link
Contributor

Hi everyone,

After further investigation we have reached a conclusion that this operation is working as expected. This was provided as a convenience method so that customers wont have to implement the Enhanced (simplified) auth flow explicitly. It works the same way as if you were to call the underlying methods directly with the Cognito client.

In order to supply an explicit session policy that allows SSM / any other operations that are not allowed on the Default Session Policy, you will need to use a different auth flow. For example, the "Basic (classic) authflow" which would require you to use Cognito client to call GetId(), and GetOpenIdToken(), and after getting the token, you will need to use STS client to call assumeRoleWithWebIdentity() which takes a session policy (Policy) as an argument.

I have created a doc update to highlight this limitation.

At this time we have no plan on adding / expanding this convenience method as it doesn't exist in all SDKs. If you would like to see it being added, you can create a feature request in the aws-sdk general repo, there it will be prioritized based on customer engagement (upvotes, comments, etc)

Thanks again for all of your patience,
Ran~

@nickcorbett15
Copy link

I am also having this issue for access to IotTwinMaker resources. I can query S3 buckets fine but cannot access any twinMaker resources.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug This issue is a bug. needs-review This issue/pr needs review from an internal developer. p2 This is a standard priority issue
Projects
None yet
Development

No branches or pull requests

4 participants