aws-amplify / amplify-cli

The AWS Amplify CLI is a toolchain for simplifying serverless web and mobile development.
Apache License 2.0
2.81k stars 821 forks source link

support `NotResource` in function's `custom-policies.json` #9871

Open jamime opened 2 years ago

jamime commented 2 years ago

Before opening, please confirm:

How did you install the Amplify CLI?

npm

If applicable, what version of Node.js are you using?

v16.14.0

Amplify CLI Version

7.6.22

What operating system are you using?

Mac

Did you make any manual changes to the cloud resources managed by Amplify? Please describe the changes made.

No manual changes made

Amplify Categories

function

Amplify Commands

push

Describe the bug

Unable to use NotResource in amplify/backend/function/authCreateAuthChallenge/custom-policies.json. I want to grant access to SNS publish to all mobile numbers, but not a SNS topic.

[
  {
    "Effect": "Allow",
    "Action": [
        "sns:Publish"
    ],
    "NotResource": "arn:aws:sns:*:*:*"
  }
]
Error: Invalid custom IAM policies in the authCreateAuthChallenge function.

    Edit <project-dir>/amplify/backend/function/authCreateAuthChallenge/custom-policies.json to fix
    Learn more about custom IAM policies for function: https://docs.amplify.aws/cli/function/#access-existing-aws-resource-from-lambda-function
should have required property 'Resource'

Expected behavior

amplify push function authCreateAuthChallenge should work with this policy file.

Reproduction steps

  1. amplify init
  2. amplify add function and name it authCreateAuthChallenge.
  3. Update amplify/backend/function/authCreateAuthChallenge/custom-policies.json to include
[
  {
    "Effect": "Allow",
    "Action": [
        "sns:Publish"
    ],
    "NotResource": "arn:aws:sns:*:*:*"
  }
]

GraphQL schema(s)

```graphql # Put schemas below this line ```

Log output

``` 2022-02-28T12:02:46.963Z|info : amplify version core {"version":true,"yes":false} 2022-02-28T12:04:45.446Z|info : amplify push function authCreateAuthChallenge 2022-02-28T12:04:45.484Z|info : amplify-cli-core.banner-message/index.ts.fetch banner messages from https://aws-amplify.github.io/amplify-cli/banner-message.json({} 2022-02-28T12:05:49.703Z|info : amplify-provider-awscloudformation.system-config-manager.getProfileConfig(["[***]"]) 2022-02-28T12:05:49.705Z|info : amplify-provider-awscloudformation.system-config-manager.getProfiledAwsConfig.profileConfig([{"region":"eu-west-2"}]) 2022-02-28T12:05:49.705Z|info : amplify-provider-awscloudformation.system-config-manager.getProfileCredentials(["[***]"]) 2022-02-28T12:05:49.928Z|info : amplify-provider-awscloudformation.aws-s3.uploadFile.s3.putObject([{"Key":"[***]ify-[***]fn-[***]ates/[***]th/[***]th-[***]ger-[***]mation-[***]e.json","Bucket":"[***]ify-[***]ing-[***]ev-[***]837-[***]ment"}]) 2022-02-28T12:05:50.896Z|info : amplify-provider-awscloudformation.push-resources.packageResources.s3.uploadFile([{"Key":"[***]ify-[***]lds/[***]hChallenge-[***]6a536532-[***].zip"}]) 2022-02-28T12:05:50.897Z|info : amplify-provider-awscloudformation.aws-s3.uploadFile.s3.putObject([{"Key":"[***]ify-[***]lds/[***]hChallenge-[***]6a536532-[***].zip","Bucket":"[***]ify-[***]ing-[***]ev-[***]837-[***]ment"}]) 2022-02-28T12:05:51.248Z|error : amplify-provider-awscloudformation.push-resources.run([{"resourcesToBeCreated":[],"resourcesToBeUpdated":[{"build":true,"providerPlugin":"[***]rmation","service":"Lambda","lastBuildTimeStamp":"2022-02-28T12:05:50.861Z","lastBuildType":"PROD","lastPackageTimeStamp":"2022-02-28T12:01:43.941Z","distZipFilename":"[***]hChallenge-[***]6a536532-[***].zip","s3Bucket":{"deploymentBucketName":"[***]ify-[***]ing-[***]ev-[***]837-[***]ment","s3Key":"[***]ify-[***]lds/[***]hChallenge-[***]6a536532-[***].zip"},"providerMetadata":{"s3TemplateURL":"https://s3.amazonaws.com/[***]ify-[***]ing-[***]ev-[***]837-[***]ment/amplify-cfn-templates/function/[***]hChallenge-cloudformation-template.json","logicalId":"[***]AuthChallenge"},"lastPushTimeStamp":"2022-02-27T18:05:11.897Z","output":{"Region":"eu-west-2","Arn":"[***]mbda:eu-[***]st-[***]CreateAuthChallenge-[***]ev","Name":"[***]hChallenge-[***]ev","LambdaExecutionRole":"[***]hChallenge-[***]ev"},"lastPushDirHash":"[***]=","resourceName":"[***]hChallenge","category":"function"}],"resourcesToBeSynced":[],"resourcesToBeDeleted":[],"rootStackUpdated":false,"tagsUpdated":false,"allResources":[{"build":true,"providerPlugin":"[***]rmation","service":"Lambda","lastBuildTimeStamp":"2022-02-28T12:05:50.861Z","lastBuildType":"PROD","lastPackageTimeStamp":"2022-02-28T12:01:43.941Z","distZipFilename":"[***]hChallenge-[***]6a536532-[***].zip","s3Bucket":{"deploymentBucketName":"[***]","s3Key":"[***]ify-[***]lds/[***]hChallenge-[***]6a536532-[***].zip"},"providerMetadata":{"s3TemplateURL":"https://s3.amazonaws.com/[***]/amplify-cfn-templates/function/authCreateAuthChallenge-cloudformation-template.json","logicalId":"[***]AuthChallenge"},"lastPushTimeStamp":"2022-02-27T18:05:11.897Z","output":{"Region":"eu-west-2","Arn":"[***]mbda:eu-[***]st-[***]CreateAuthChallenge-[***]ev","Name":"authCreateAuthChallenge-dev","LambdaExecutionRole":"authCreateAuthChallenge-dev"},"lastPushDirHash":"/[***]=","resourceName":"authCreateAuthChallenge","category":"function"}]}]) Error: Invalid custom IAM policies in the authCreateAuthChallenge function. Edit /amplify/backend/function/authCreateAuthChallenge/custom-policies.json to fix Learn more about custom IAM policies for function: https://docs.amplify.aws/cli/function/#access-existing-aws-resource-from-lambda-function should have required property 'Resource' ```

Additional information

I can set an inline policy using the same document via the AWS console.

josefaidt commented 2 years ago

Hey @jamime :wave: thanks for raising this! Can you try to set NotResource's value to an array? https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_notresource.html

jamime commented 2 years ago

Using an array gives the same error message.

should have required property 'Resource'

[
  {
    "Effect": "Allow",
    "Action": [
        "sns:Publish"
    ],
    "NotResource": ["arn:aws:sns:*:*:*"]
  }
]
josefaidt commented 2 years ago

Hey @jamime thanks for the clarification! I will mark this as a feature request to support NotResource, however in the mean time can you see if mixing DENY/ALLOW policies will accomplish this?

[
  {
    "Effect": "Deny",
    "Action": ["sns:Publish"],
    "Resource": ["arn:aws:sns:*:*:*"]
  },
  {
    "Effect": "Allow",
    "Action": ["sns:Publish"],
    "Resource": ["*"]
  }
]

Using the following Lambda code we are able to send messages via SMS

import { SNSClient, PublishCommand } from '@aws-sdk/client-sns'
const client = new SNSClient()

/**
 * Publish a message to a phone number
 * @param {string} number - phone number of recipient
 * @param {string} [message] - message to send to phone number
 * @returns {import('@aws-sdk/client-sns').PublishCommandOutput}
 */
async function publish(number, message) {
  /** @type {import('@aws-sdk/client-sns').PublishCommandInput} */
  const input = {
    PhoneNumber: number || '+5555555555',
    Message: message || 'SMS from Lambda!',
  }

  /** @type {import('@aws-sdk/client-sns').PublishCommand} */
  const command = new PublishCommand(input)
  const response = await client.send(command)
  return response
}

/**
 * @type {import('@types/aws-lambda').APIGatewayProxyHandler}
 */
export async function handler(event) {
  const { number, message } = event?.body || {}
  const response = await publish(number, message)
  return {
    statusCode: 200,
    body: JSON.stringify(response),
  }
}