S3 upload works on sls offline but don't work after sls deploy on real aws api url

s3 upload works on sls offline but don’t work after sls deploy on real aws api url

after sls deploy and I get the endpoint url and try to upload image but it give access denied error on my catch block thing of s3.putObject but on sls offline local it work and in s3 bucket I can see files but after deploying it’s not uploading and giving access denied.

Real Api After Deploy vs Localhost:

serverless.yml is bellow


org: alvee
app: barikhojo-backend
service: barikhojo-backend
frameworkVersion: '3'

provider:
  name: aws
  region: ap-southeast-1
  runtime: nodejs18.x
  stage: dev
  iam:
    role:
      statements:
      - Effect: Allow
        Action:
        - "s3:*"
        Resource: "arn:aws:s3:::${self:custom.imagesBucketName}" 
      - Effect: Allow
        Action: 
        - 'dynamodb:PutItem'    
        - 'dynamodb:Get*'    
        - 'dynamodb:Scan'    
        - 'dynamodb:Query'    
        - 'dynamodb:UpdateItem'    
        - 'dynamodb:DeleteItem'    
        Resource: "arn:aws:dynamodb:${aws:region}:${aws:accountId}:table/${self:custom.propertyTable}"
  environment: 
    BUCKET_NAME: ${self:custom.imagesBucketName}
    PROPERTY_TABLE: ${self:custom.propertyTable}

functions:
  api:
    handler: index.savePhoto
    events:
      - httpApi:
          path: /
          method: post


custom: 
  propertyTable: ${self:service}-property-table-${sls:stage}
  imagesBucketName: ${self:service}-s3-${sls:stage}

resources:
  Resources:

    # S3 BUCKET
    ImagesBucket: 
      Type: AWS::S3::Bucket
      Properties:
        BucketName: ${self:custom.imagesBucketName}

        # Granting public access to bucket
        PublicAccessBlockConfiguration:
          BlockPublicAcls: false
          BlockPublicPolicy: false
          IgnorePublicAcls: false
          RestrictPublicBuckets: false
    ImagesBucketAllowPublicReadPolicy:
      Type: AWS::S3::BucketPolicy
      Properties:
        Bucket: !Ref ImagesBucket
        PolicyDocument:
          Version: "2012-10-17"
          Statement: 
            - Sid: AllowPublicReadAccess
              Effect: Allow
              Action: 
                - "s3:GetObject"
              Resource: 
                - !Join ['/', [!GetAtt [ImagesBucket, Arn], '*']]
              Principal: "*"    
              Condition:
                Bool:
                  aws:SecureTransport: 'true'
  
    # DynamoDB 
    PropertyTable:
      Type: AWS::DynamoDB::Table
      Properties:
        TableName: ${self:custom.propertyTable}
        AttributeDefinitions:
          - AttributeName: ID
            AttributeType: S           
        KeySchema:
          - AttributeName: ID
            KeyType: HASH
        BillingMode: PAY_PER_REQUEST
        

plugins:
  - serverless-offline
  - serverless-plugin-common-excludes

lambda function code


const AWS = require('aws-sdk')
const parser = require("lambda-multipart-parser")
const { v4: uuidv4 } = require("uuid")

const s3 = new AWS.S3();
const BucketName = process.env.BUCKET_NAME;

async function saveFile(file){
  try {
    const savedFile = await s3.putObject({
      Bucket: BucketName,
      Key: `${file.filename}-${uuidv4()}`,
      Body: file.content
    }).promise()
    return 'done'
  } catch (error) {
    return error
  }
} 

module.exports.savePhoto = async (event) => {
  const {files} = await parser.parse(event)
 
  const status = await saveFile(files[0])

  return {
    statusCode: 200,
    body: JSON.stringify(
      {
        message: "Go Serverless v3.0! Your function executed successfully!",
        input: 'File Uploaded',
        bucketName: BucketName,
        status: status,
        filename: files[0].filename
      },
      null,
      2
    ),
  };
};